From 6cbe71ce9d4a7ee8ec617a4f13793520b91e1b98 Mon Sep 17 00:00:00 2001 From: setkyar Date: Tue, 16 Aug 2016 22:31:00 +0630 Subject: [PATCH 1/5] WIP of translating scout --- scout.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/scout.md b/scout.md index 380202f..9e12c3c 100644 --- a/scout.md +++ b/scout.md @@ -1,6 +1,6 @@ # Laravel Scout -- [Introduction](#introduction) +- [မိတ်ဆက်](#introduction) - [Installation](#installation) - [Queueing](#queueing) - [Driver Prerequisites](#driver-prerequisites) @@ -18,28 +18,28 @@ - [Pagination](#pagination) -## Introduction +## မိတ်ဆက် -Laravel Scout provides a simple, driver based solution for adding full-text search to your [Eloquent models](/docs/{{version}}/eloquent). Using model observers, Scout will automatically keep your search indexes in sync with your Eloquent records. +[Eloquent models](/docs/{{version}}/eloquent) အတွက် full-text search ကို Laravel Scout ကလွယ်ကူတဲ့ driver based solution အဖြစ်ပြုလုပ်ပေးထားပါတယ်။ Model observers တွေကိုသုံးပြီးတော့ search indexes အဖြစ် Eloquent records တွေနဲ့အလိုအလျောက် sync လုပ်ပေးမှာဖြစ်ပါတယ်။ -Currently, Scout ships with an [Algolia](https://www.algolia.com/) driver; however, writing custom drivers is simple and you are free to extend Scout with your own search implementations. +လက်ရှိမှာတော့ Scout ကို [Algolia](https://www.algolia.com/) driver နဲ့ ship လုပ်ပေးမှာဖြစ်ပါတယ်၊ ဒါပေမယ့် custom drivers တွေပြုလုပ်ရတာကလွယ်ကူတော့ Scout ကို extend လုပ်ပြီးတော့ကိုယ်ပိုင် search implementations တွေလည်းပြုလုပ်နိုင်ပါတယ်။ ## Installation -First, install the Scout via the Composer package manager: +ပထမဆုံး Scout ကို Composer package manager ကနေ install လုပ်လိုက်ပါ - composer require laravel/scout -Next, you should add the `ScoutServiceProvider` to the `providers` array of your `config/app.php` configuration file: +ပြီးရင်တော့ `ScoutServiceProvider` ကို `config/app.php` array configuration file မှာထည့်လိုက်ပါ - Laravel\Scout\ScoutServiceProvider::class, -After registering the Scout service provider, you should publish the Scout configuration using the `vendor:publish` Artisan command. This command will publish the `scout.php` configuration file to your `config` directory: +Scout service provider ကို register လုပ်ပြီးပြီဆိုရင် Scout configuration ကို `vendor:publish` Artisan command run ပြီးတော့ publish လုပ်လိုက်ပါ။ ဒီ publish command run လိုက်တာနဲ့ `config` directory မှာ `scout.php` configuration file ကို publish လုပ်သွားမှာဖြစ်ပါတယ် - php artisan vendor:publish -Finally, add the `Laravel\Scout\Searchable` trait to the model you would like to make searchable. This trait will register a model observer to keep the model in sync with your search driver: +နောက်ဆုံးအဆင့်အနေနဲ့ကတော့ `Laravel\Scout\Searchable` trait ကိုကိုယ်ရှာစေချင်တဲ့ Model မှာထည့်ပါ။ အဲ့ဒီ့ trait က model နဲ့ search driver ကြားမှာ sync လုပ်အောင် model observer တစ်ခု register လုပ်ပါလိမ့်မယ်။ - {{ $orders->links() }} + {{ $orders->links() }} \ No newline at end of file From a842d2fc15f99e0bb1b713064f4563178e1066f3 Mon Sep 17 00:00:00 2001 From: Set Kyar Wa Lar Date: Thu, 17 Nov 2016 14:26:10 +0630 Subject: [PATCH 2/5] Add 4.2 translation --- api-authentication.md | 523 ------------- apis.md | 0 application-testing.md | 351 --------- artisan.md | 392 +--------- authentication.md | 502 ------------- authorization.md | 314 -------- billing.md | 652 ++++------------ blade.md | 366 --------- broadcasting.md | 455 ------------ cache.md | 353 ++------- collections.md | 1367 ---------------------------------- commands.md | 142 ++++ configuration.md | 158 ++-- container.md | 249 ------- contracts.md | 205 ----- contributing.md | 18 +- contributions.md | 82 -- controllers.md | 355 ++++----- csrf.md | 69 -- database-testing.md | 226 ------ database.md | 251 ++----- documentation.md | 120 ++- elixir.md | 351 --------- eloquent-collections.md | 146 ---- eloquent-mutators.md | 210 ------ eloquent-relationships.md | 882 ---------------------- eloquent-serialization.md | 147 ---- eloquent.md | 1478 +++++++++++++++++++++++++------------ encryption.md | 63 -- envoy.md | 180 ----- errors.md | 210 ++---- events.md | 334 +++------ extending.md | 223 ++++++ facades.md | 251 +++---- filesystem.md | 326 -------- hashing.md | 58 -- helpers.md | 946 ++++++------------------ homestead.md | 256 ++----- html.md | 197 +++++ installation.md | 101 +-- introduction.md | 25 + ioc.md | 186 +++++ license.md | 2 +- lifecycle.md | 84 ++- localization.md | 122 +-- mail.md | 442 ++--------- middleware.md | 250 ------- migrations.md | 411 ++--------- mocking.md | 178 ----- notifications.md | 637 ---------------- packages.md | 401 +++++----- pagination.md | 207 +++--- passwords.md | 79 -- providers.md | 160 ---- queries.md | 604 +++++---------- queues.md | 578 ++++----------- quick.md | 178 +++++ readme.md | 16 +- redirects.md | 88 --- redis.md | 171 ++--- releases.md | 517 +------------ requests.md | 358 ++++----- responses.md | 315 ++++---- routing.md | 454 +++++++----- scheduling.md | 198 ----- schema.md | 216 ++++++ scout.md | 263 ------- security.md | 310 ++++++++ seeding.md | 94 --- session.md | 286 ++----- ssh.md | 263 +++++++ structure.md | 156 ---- summary.md | 47 ++ templates.md | 180 +++++ testing.md | 231 +++++- upgrade.md | 1182 +---------------------------- valet.md | 230 ------ validation.md | 1006 +++++++------------------ views.md | 200 ----- 79 files changed, 6298 insertions(+), 18536 deletions(-) delete mode 100644 api-authentication.md delete mode 100644 apis.md delete mode 100644 application-testing.md delete mode 100644 authentication.md delete mode 100644 authorization.md delete mode 100644 blade.md delete mode 100644 broadcasting.md delete mode 100644 collections.md create mode 100644 commands.md delete mode 100644 container.md delete mode 100644 contracts.md delete mode 100644 contributions.md delete mode 100644 csrf.md delete mode 100644 database-testing.md delete mode 100644 elixir.md delete mode 100644 eloquent-collections.md delete mode 100644 eloquent-mutators.md delete mode 100644 eloquent-relationships.md delete mode 100644 eloquent-serialization.md delete mode 100644 encryption.md delete mode 100644 envoy.md create mode 100644 extending.md delete mode 100644 filesystem.md delete mode 100644 hashing.md create mode 100644 html.md create mode 100644 introduction.md create mode 100644 ioc.md mode change 100644 => 100755 lifecycle.md mode change 100644 => 100755 localization.md mode change 100644 => 100755 mail.md delete mode 100644 middleware.md mode change 100644 => 100755 migrations.md delete mode 100644 mocking.md delete mode 100644 notifications.md mode change 100644 => 100755 packages.md mode change 100644 => 100755 pagination.md delete mode 100644 passwords.md delete mode 100644 providers.md mode change 100644 => 100755 queries.md mode change 100644 => 100755 queues.md create mode 100755 quick.md mode change 100644 => 100755 readme.md delete mode 100644 redirects.md mode change 100644 => 100755 redis.md mode change 100644 => 100755 releases.md mode change 100644 => 100755 requests.md mode change 100644 => 100755 responses.md mode change 100644 => 100755 routing.md delete mode 100644 scheduling.md create mode 100755 schema.md delete mode 100644 scout.md create mode 100755 security.md delete mode 100644 seeding.md mode change 100644 => 100755 session.md create mode 100755 ssh.md delete mode 100644 structure.md create mode 100755 summary.md create mode 100755 templates.md mode change 100644 => 100755 testing.md mode change 100644 => 100755 upgrade.md delete mode 100644 valet.md mode change 100644 => 100755 validation.md delete mode 100644 views.md diff --git a/api-authentication.md b/api-authentication.md deleted file mode 100644 index 623d992..0000000 --- a/api-authentication.md +++ /dev/null @@ -1,523 +0,0 @@ -# API Authentication (Passport) - -- [Introduction](#introduction) -- [Installation](#installation) - - [Configuration](#configuration) - - [Frontend Quickstart](#frontend-quickstart) -- [OAuth2 Using Authorization Codes](#oauth2-using-authorization-codes) - - [Managing Clients](#managing-clients) - - [Requesting Tokens](#requesting-tokens) - - [Refreshing Tokens](#refreshing-tokens) -- [Personal Access Tokens](#personal-access-tokens) - - [Creating A Personal Access Client](#) - - [Managing Personal Access Tokens](#) -- [Protecting Routes](#protecting-routes) - - [Via Middleware](#via-middleware) - - [Passing The Access Token](#passing-the-access-token) -- [Token Scopes](#token-scopes) - - [Defining Scopes](#defining-scopes) - - [Assigning Scopes To Tokens](#assigning-scopes-to-tokens) - - [Checking Scopes](#checking-scopes) -- [Consuming Your API With JavaScript](#consuming-your-api-with-javascript) - - -## Introduction - -Laravel already makes it easy to perform authentication via traditional login forms, but what about APIs? APIs typically use tokens to authenticate users and do not maintain session state between requests. Laravel makes API authentication a breeze using Laravel Passport, which provides a full OAuth2 server implementation for your Laravel application in a matter of minutes. Passport is built on top of the [League OAuth2 server](https://github.com/thephpleague/oauth2-server) that is maintained by Alex Bilbie. - -> {note} This documentation assumes you are already familiar with OAuth2. If you do not know anything about OAuth2, consider familiarizing yourself with the general terminology and features of OAuth2 before continuing. - - -## Installation - -To get started, install Passport via the Composer package manager: - - composer require laravel/passport - -Next, register the Passport service provider in the `providers` array of your `config/app.php` configuration file: - - Laravel\Passport\PassportServiceProvider::class, - -The Passport service provider registers its own database migration directory with the framework, so you should migrate your database after registering the provider. The Passport migrations will create the tables your application needs to store clients and access tokens: - - php artisan migrate - -Next, you should run the `passport:install` command. This command will create the encryption keys needed to generate secure access tokens. In addition, the command will create a "personal access" client which will be used to generate personal access tokens: - - php artisan passport:install - -After running this command, add the `Laravel\Passport\HasApiTokens` trait to your `App\User` model. This trait will provide a few helper methods to your model which allow you to inspect the authenticated user's token and scopes: - - 'App\Policies\ModelPolicy', - ]; - - /** - * Register any authentication / authorization services. - * - * @return void - */ - public function boot() - { - $this->registerPolicies(); - - Passport::routes(); - } - } - -Finally, in your `config/auth.php` configuration file, you should set the `driver` option of the `api` authentication guard to `passport`. This will instruct your application to use Passport's `TokenGuard` when authenticating incoming API requests: - - 'guards' => [ - 'web' => [ - 'driver' => 'session', - 'provider' => 'users', - ], - - 'api' => [ - 'driver' => 'passport', - 'provider' => 'users', - ], - ], - - -### Configuration - -#### Token Lifetimes - -By default, Passport issues long-lived access tokens that never need to be refreshed. If you would like to configure a shorter token lifetime, you may use the `tokensExpireIn` and `refreshTokensExpireIn` methods. These methods should be called from the `boot` method of your `AuthServiceProvider`: - - /** - * Register any authentication / authorization services. - * - * @return void - */ - public function boot() - { - $this->registerPolicies(); - - Passport::routes(); - - Passport::tokensExpireIn(Carbon::now()->addDays(15)); - - Passport::refreshTokensExpireIn(Carbon::now()->addDays(30)); - } - - -### Frontend Quickstart - -> {note} In order to use the Passport Vue components, you must be using the [Vue](https://vuejs.org) JavaScript framework. These components also use the Bootstrap CSS framework. However, even if you are not using these tools, the components serve as a valuable reference for your own frontend implementation. - -Passport ships with a JSON API that you may use to allow your users to create clients and personal access tokens. However, it can be time consuming to code a frontend to interact with these APIs. So, Passport also includes pre-built [Vue](https://vuejs.org) components you may use as an example implementation or starting point for your own implementation. - -To publish the Passport Vue components, use the `vendor:publish` Artisan command: - - php artisan vendor:publish --tag=passport-components - -The published components will be placed in your `resources/assets/js/components` directory. Once the components have been published, you should register them in your `resources/assets/js/app.js` file: - - Vue.component( - 'passport-clients', - require('./components/passport/Clients.vue') - ); - - Vue.component( - 'passport-authorized-clients', - require('./components/passport/AuthorizedClients.vue') - ); - - Vue.component( - 'passport-personal-access-tokens', - require('./components/passport/PersonalAccessTokens.vue') - ); - -Once the components have been registered, you may drop them into one of your application's templates to get started creating clients and personal access tokens: - - - - - - -## OAuth2 Using Authorization Codes - -Using OAuth2 with authorization codes is how most developers are familiar with OAuth2. When using authorization codes, a client application will redirect a user to your server where they will either approve or deny the request to issue an access token to the client. - - -### Managing Clients - -First, developers building applications that need to interact with your application's API will need to register their application with yours by creating a "client". Typically, this consists of providing the name of their application and a URL that your application can redirect to after users approve their request for authorization. - -#### The `passport:client` Command - -The simplest way to create a client is using the `passport:client` Artisan command. This command may be used to create your own clients for testing your OAuth2 functionality. When you run the `client` command, Passport will prompt you for more information about your client and will provide you with a client ID and secret: - - php artisan passport:client - -#### JSON API - -Since your users will not be able to utilize the `client` command, Passport provides a JSON API that you may use to create clients. This saves you the trouble of having to manually code controllers for creating, updating, and deleting clients. - -However, you will need to pair Passport's JSON API with your own frontend to provide a dashboard for your users to manage their clients. Below, we'll review all of the API endpoints for managing clients. For convenience, we'll use [Vue](https://vuejs.org) to demonstrate making HTTP requests to the endpoints. - -> {tip} The routes to send requests to the Passport controllers were registered when you called the `Passport::routes` method in your `AuthServiceProvider`. - -#### `GET /oauth/clients` - -This route returns all of the clients for the authenticated user. This is primarily useful for listing all of the user's clients so that they may edit or delete them: - - this.$http.get('/oauth/clients') - .then(response => { - console.log(response.data); - }); - -#### `POST /oauth/clients` - -This route is used to create new clients. It requires two pieces of data: the client's `name` and a `redirect` URL. The `redirect` URL is where the user will be redirected after approving or denying a request for authorization. - -When a client is created, it will be issued a client ID and client secret. These values will be used when requesting access tokens from your application. The client creation route will return the new client instance: - - const data = { - name: 'Client Name', - redirect: 'http://example.com/callback' - }; - - this.$http.post('/oauth/clients', data) - .then(response => { - console.log(response.data); - }) - .catch (response => { - // List errors on response... - }); - -#### `PUT /oauth/clients/{client-id}` - -This route is used to update clients. It requires two pieces of data: the client's `name` and a `redirect` URL. The `redirect` URL is where the user will be redirected after approving or denying a request for authorization. The route will return the updated client instance: - - const data = { - name: 'New Client Name', - redirect: 'http://example.com/callback' - }; - - this.$http.put('/oauth/clients/' + clientId, data) - .then(response => { - console.log(response.data); - }) - .catch (response => { - // List errors on response... - }); - -#### `DELETE /oauth/clients/{client-id}` - -This route is used to delete clients: - - this.$http.delete('/oauth/clients/' + clientId) - .then(response => { - // - }); - - -### Requesting Tokens - -#### Redirecting For Authorization - -Once a client has been created, developer's may use their client ID and secret to request an authorization code and access token from your application. First, the consuming application should make a redirect request to your application's `/oauth/authorize` route like so: - - Route::get('/redirect', function () { - $query = http_build_query([ - 'client_id' => 'client-id', - 'redirect_uri' => 'http://example.com/callback', - 'response_type' => 'code', - 'scope' => '', - ]); - - return redirect('http://your-app.com/oauth/authorize?'.$query); - }); - -> {tip} Remember, the `/oauth/authorize` route is already defined by the `Passport::routes` method. You do not need to manually define this route. - -#### Approving The Request - -When receiving authorization requests, Passport will automatically display a template to the user allowing them to approve or deny the authorization request. If they approve the request, they will be redirected back to the `redirect_uri` that was specified by the consuming application. The `redirect_uri` must match the `redirect` URL that was specified when the client was created. - -If you would like to customize the authorization approval screen, you may publish Passport's views using the `vendor:publish` Artisan command. The published views will be placed in `resources/views/vendor/passport`: - - php artisan vendor:publish --tag=passport-views - -#### Converting Authorization Codes To Access Tokens - -If the user approves the authorization request, they will be redirected back to the consuming application. The consumer should then issue a `POST` request to your application to request an access token. The request should include the authorization code that was issued by when the user approved the authorization request. In this example, we'll use the Guzzle HTTP library to make the `POST` request: - - Route::get('/callback', function (Request $request) { - $http = new GuzzleHttp\Client; - - $response = $http->post('http://your-app.com/oauth/token', [ - 'form_params' => [ - 'grant_type' => 'authorization_code', - 'client_id' => 'client-id', - 'client_secret' => 'client-secret', - 'redirect_uri' => 'http://example.com/callback', - 'code' => $request->code, - ], - ]); - - return json_decode((string) $response->getBody(), true); - }); - -This `/oauth/token` route will return a JSON response containing `access_token`, `refresh_token`, and `expires_in` attributes. The `expires_in` attribute contains the number of seconds until the access token expires. - -> {tip} Like the `/oauth/authorize` route, the `/oauth/token` route is defined for you by the `Passport::routes` method. There is no need to manually define this route. - - -### Refreshing Tokens - -If your application issues short-lived access tokens, users will need to refresh their access tokens via the refresh token that was provided to them when the access token was issued. In this example, we'll use the Guzzle HTTP library to refresh the token: - - $http = new GuzzleHttp\Client; - - $response = $http->post('http://your-app.com/oauth/token', [ - 'form_params' => [ - 'grant_type' => 'refresh_token', - 'refresh_token' => 'the-refresh-token', - 'client_id' => 'client-id', - 'client_secret' => 'client-secret', - 'scope' => '', - ], - ]); - - return json_decode((string) $response->getBody(), true); - -This `/oauth/token` route will return a JSON response containing `access_token`, `refresh_token`, and `expires_in` attributes. The `expires_in` attribute contains the number of seconds until the access token expires. - - -## Personal Access Tokens - -Sometimes, your users may want to issue access tokens to themselves without going through the typical authorization code redirect flow. Allowing users to issue tokens to themselves via your application's UI can be useful for allowing users to experiment with your API or may serve as a simpler approach to issuing access tokens in general. - -> {note} Personal access tokens are always long-lived. Their lifetime is not modified when using the `tokensExpireIn` or `refreshTokensExpireIn` methods. - - -### Creating A Personal Access Client - -Before your application can issue personal access tokens, you will need to create a personal access client. You may do this using the `passport:client` command with the `--personal` option. If you have already run the `passport:install` command, you do not need to run this command: - - php artisan passport:client --personal - - -### Managing Personal Access Tokens - -Once you have created a personal access client, you may issue tokens for a given user using the `createToken` method on the `User` model instance. The `createToken` method accepts the name of the token as its first argument and an optional array of [scopes](#token-scopes) as its second argument: - - $user = App\User::find(1); - - // Creating a token without scopes... - $token = $user->createToken('Token Name')->accessToken; - - // Creating a token with scopes... - $token = $user->createToken('My Token', ['place-orders'])->accessToken; - -#### JSON API - -Passport also includes a JSON API for managing personal access tokens. You may pair this with your own frontend to offer your users a dashboard for managing personal access tokens. Below, we'll review all of the API endpoints for managing personal access tokens. For convenience, we'll use [Vue](https://vuejs.org) to demonstrate making HTTP requests to the endpoints. - -#### `GET /oauth/scopes` - -This route returns all of the [scopes](#scopes) defined for your application. You may use this route to list the scopes a user may assign to a personal access token: - - this.$http.get('/oauth/scopes') - .then(response => { - console.log(response.data); - }); - -#### `GET /oauth/personal-access-tokens` - -This route returns all of the personal access tokens that the authenticated user has created. This is primarily useful for listing all of the user's token so that they may edit or delete them: - - this.$http.get('/oauth/personal-access-tokens') - .then(response => { - console.log(response.data); - }); - -#### `POST /oauth/personal-access-tokens` - -This route creates new personal access tokens. It requires two pieces of data: the token's `name` and the `scopes` that should be assigned to the token: - - const data = { - name: 'Token Name', - scopes: [] - }; - - this.$http.post('/oauth/personal-access-tokens', data) - .then(response => { - console.log(response.data.accessToken); - }) - .catch (response => { - // List errors on response... - }); - -#### `DELETE /oauth/personal-access-tokens/{token-id}` - -This route may be used to delete personal access tokens: - - this.$http.delete('/oauth/personal-access-tokens/' + tokenId); - - -## Protecting Routes - - -### Via Middleware - -Passport includes an [authentication guard](/docs/{{version}}/authentication#adding-custom-guards) that will validate access tokens on incoming requests. Once you have configured the `api` guard to use the `passport` driver, you only need to specify the `auth:api` middleware on any routes that require a valid access token: - - Route::get('/user', function () { - // - })->middleware('auth:api'); - -> {tip} The `RouteServiceProvider` included with fresh Laravel applications already loads the `api` route file within a route group containing the `auth:api` middleware. So, there is no need to manually assign this middleware routes in your `api` routes file. - - -### Passing The Access Token - -When calling routes that are protected by Passport, your application's API consumers should specify their access token as a `Bearer` token in the `Authorization` header of their request. For example, when using the Guzzle HTTP library: - - $response = $client->request('GET', '/api/user', [ - 'headers' => [ - 'Accept' => 'application/json', - 'Authorization' => 'Bearer '.$accessToken, - ], - ]); - - -## Token Scopes - - - -### Defining Scopes - -Scopes allow your API clients to request a specific set of permissions when requesting authorization to access an account. For example, if you are building an e-commerce application, not all API consumers will need the ability to place orders. Instead, you may allow the consumers to only request authorization to access order shipment statuses. In other words, scopes allow your application's users to limit the actions a third-party application can perform on their behalf. - -You may define your API's scopes using the `Passport::tokensCan` method in the `boot` method of your `AuthServiceProvider`. The `tokensCan` method accepts an array of scope names and scope descriptions. The scope description may be anything you wish and will be displayed to users on the authorization approval screen: - - use Laravel\Passport\Passport; - - Passport::tokensCan([ - 'place-orders' => 'Place orders', - 'check-status' => 'Check order status', - ]); - - -### Assigning Scopes To Tokens - -#### When Requesting Authorization Codes - -When requesting an access token using the authorization code grant, consumers should specify their desired scopes as the `scope` query string parameter. The `scope` parameter should be a space-delimited list of scopes: - - Route::get('/redirect', function () { - $query = http_build_query([ - 'client_id' => 'client-id', - 'redirect_uri' => 'http://example.com/callback', - 'response_type' => 'code', - 'scope' => 'place-orders check-status', - ]); - - return redirect('http://your-app.com/oauth/authorize?'.$query); - }); - -#### When Issuing Personal Access Tokens - -If you are issuing personal access tokens using the `User` model's `createToken` method, you may pass the array of desired scopes as the second argument to the method: - - $token = $user->createToken('My Token', ['place-orders'])->accessToken; - - -### Checking Scopes - -Passport includes two middleware that may be used to verify that an incoming request is authenticated with a token that has been granted a given scope. To get started, add the following middleware to the `$routeMiddleware` property of your `app/Http/Kernel.php` file: - - 'scopes' => \Laravel\Passport\Http\Middleware\CheckScopes::class, - 'scope' => \Laravel\Passport\Http\Middleware\CheckForAnyScope::class, - -#### Check For All Scopes - -The `scopes` middleware may be assigned to a route to verify that the incoming request's access token has *all* of the listed scopes: - - Route::get('/orders', function () { - // Access token has both "check-status" and "place-orders" scopes... - })->middleware('scopes:check-status,place-orders'); - -#### Check For Any Scopes - -The `scope` middleware may be assigned to a route to verify that the incoming request's access token has *at least one* of the listed scopes: - - Route::get('/orders', function () { - // Access token has either "check-status" or "place-orders" scope... - })->middleware('scope:check-status,place-orders'); - -#### Checking Scopes On A Token Instance - -Once an access token authenticated request has entered your application, you may still check if the token has a given scope using the `tokenCan` method on the authenticated `User` instance: - - use Illuminate\Http\Request; - - Route::get('/orders', function (Request $request) { - if ($request->user()->tokenCan('place-orders')) { - // - } - }); - - -## Consuming Your API With JavaScript - -When building an API, it can be extremely useful to be able to consume your own API from your JavaScript application. This approach to API development allows your own application to consume the same API that you are sharing with the world. The same API may be consumed by your web application, mobile applications, third-party applications, and any SDKs that you may publish on various package managers. - -Typically, if you want to consume your API from your JavaScript application, you would need to manually send an access token to the application and pass it with each request to your application. However, Passport includes a middleware that can handle this for you. All you need to do is add the `CreateFreshApiToken` middleware to your `web` middleware group: - - 'web' => [ - // Other middleware... - \Laravel\Passport\Http\Middleware\CreateFreshApiToken::class, - ], - -This Passport middleware will attach a `laravel_token` cookie to your outgoing responses. This cookie contains an encrypted JWT that Passport will use to authenticate API requests from your JavaScript application. Now, you may make requests to your application's API without explicitly passing an access token: - - this.$http.get('/user') - .then(response => { - console.log(response.data); - }); - -When using this method of authentication, you will need to send the CSRF token with every request via the `X-CSRF-TOKEN` header. Laravel will automatically send this header if you are using the default [Vue](https://vuejs.org) configuration that is included with the framework: - - Vue.http.interceptors.push((request, next) => { - request.headers['X-CSRF-TOKEN'] = Laravel.csrfToken; - - next(); - }); - -> {note} If you are using a different JavaScript framework, you should make sure it is configured to send this header with every outgoing request. diff --git a/apis.md b/apis.md deleted file mode 100644 index e69de29..0000000 diff --git a/application-testing.md b/application-testing.md deleted file mode 100644 index 57d06e5..0000000 --- a/application-testing.md +++ /dev/null @@ -1,351 +0,0 @@ -# Application Testing - -- [Introduction](#introduction) -- [Interacting With Your Application](#interacting-with-your-application) - - [Interacting With Links](#interacting-with-links) - - [Interacting With Forms](#interacting-with-forms) -- [Testing JSON APIs](#testing-json-apis) - - [Verifying Exact Match](#verifying-exact-match) - - [Verifying Structural Match](#verifying-structural-match) -- [Sessions / Authentication](#sessions-and-authentication) -- [Disabling Middleware](#disabling-middleware) -- [Custom HTTP Requests](#custom-http-requests) -- [PHPUnit Assertions](#phpunit-assertions) - - -## Introduction - -Laravel provides a very fluent API for making HTTP requests to your application, examining the output, and even filling out forms. For example, take a look at the test defined below: - - visit('/') - ->see('Laravel 5') - ->dontSee('Rails'); - } - } - -The `visit` method makes a `GET` request into the application. The `see` method asserts that we should see the given text in the response returned by the application. The `dontSee` method asserts that the given text is not returned in the application response. This is the most basic application test available in Laravel. - -You may also use the 'visitRoute' method to make a 'GET' request via a named route: - - $this->visitRoute('profile'); - - $this->visitRoute('profile', ['user' => 1]); - - -## Interacting With Your Application - -Of course, you can do much more than simply assert that text appears in a given response. Let's take a look at some examples of clicking links and filling out forms: - - -### Interacting With Links - -In this test, we will make a request to the application, "click" a link in the returned response, and then assert that we landed on a given URI. For example, let's assume there is a link in our response that has a text value of "About Us": - - About Us - -Now, let's write a test that clicks the link and asserts the user lands on the correct page: - - public function testBasicExample() - { - $this->visit('/') - ->click('About Us') - ->seePageIs('/about-us'); - } - -You may also check that the user has arrived at the correct named route using the `seeRouteIs` method: - - ->seeRouteIs('profile', ['user' => 1]); - - -### Interacting With Forms - -Laravel also provides several methods for testing forms. The `type`, `select`, `check`, `attach`, and `press` methods allow you to interact with all of your form's inputs. For example, let's imagine this form exists on the application's registration page: - -
- {{ csrf_field() }} - -
- Name: -
- -
- Accept Terms -
- -
- -
-
- -We can write a test to complete this form and inspect the result: - - public function testNewUserRegistration() - { - $this->visit('/register') - ->type('Taylor', 'name') - ->check('terms') - ->press('Register') - ->seePageIs('/dashboard'); - } - -Of course, if your form contains other inputs such as radio buttons or drop-down boxes, you may easily fill out those types of fields as well. Here is a list of each form manipulation method: - -Method | Description -------------- | ------------- -`$this->type($text, $elementName)` | "Type" text into a given field. -`$this->select($value, $elementName)` | "Select" a radio button or drop-down field. -`$this->check($elementName)` | "Check" a checkbox field. -`$this->uncheck($elementName)` | "Uncheck" a checkbox field. -`$this->attach($pathToFile, $elementName)` | "Attach" a file to the form. -`$this->press($buttonTextOrElementName)` | "Press" a button with the given text or name. - - -#### File Inputs - -If your form contains `file` inputs, you may attach files to the form using the `attach` method: - - public function testPhotoCanBeUploaded() - { - $this->visit('/upload') - ->attach($pathToFile, 'photo') - ->press('Upload') - ->see('Upload Successful!'); - } - - -### Testing JSON APIs - -Laravel also provides several helpers for testing JSON APIs and their responses. For example, the `json`, `get`, `post`, `put`, `patch`, and `delete` methods may be used to issue requests with various HTTP verbs. You may also easily pass data and headers to these methods. To get started, let's write a test to make a `POST` request to `/user` and assert that the expected data was returned: - - json('POST', '/user', ['name' => 'Sally']) - ->seeJson([ - 'created' => true, - ]); - } - } - -> {tip} The `seeJson` method converts the given array into JSON, and then verifies that the JSON fragment occurs **anywhere** within the entire JSON response returned by the application. So, if there are other properties in the JSON response, this test will still pass as long as the given fragment is present. - - -### Verifying Exact Match - -If you would like to verify that the given array is an **exact** match for the JSON returned by the application, you should use the `seeJsonEquals` method: - - json('POST', '/user', ['name' => 'Sally']) - ->seeJsonEquals([ - 'created' => true, - ]); - } - } - - -### Verifying Structural Match - -It is also possible to verify that a JSON response adheres to a specific structure. In this scenario, you should use the `seeJsonStructure` method and pass it your expected JSON structure: - - get('/user/1') - ->seeJsonStructure([ - 'name', - 'pet' => [ - 'name', 'age' - ] - ]); - } - } - -The above example illustrates an expectation of receiving a `name` attribute and a nested `pet` object with its own `name` and `age` attributes. `seeJsonStructure` will not fail if additional keys are present in the response. For example, the test would still pass if the `pet` had a `weight` attribute. - -You may use the `*` to assert that the returned JSON structure has a list where each list item contains at least the attributes found in the set of values: - - get('/users') - ->seeJsonStructure([ - '*' => [ - 'id', 'name', 'email' - ] - ]); - } - } - -You may also nest the `*` notation. In this case, we will assert that each user in the JSON response contains a given set of attributes and that each pet on each user also contains a given set of attributes: - - $this->get('/users') - ->seeJsonStructure([ - '*' => [ - 'id', 'name', 'email', 'pets' => [ - '*' => [ - 'name', 'age' - ] - ] - ] - ]); - - -### Sessions / Authentication - -Laravel provides several helpers for working with the session during testing. First, you may set the session data to a given array using the `withSession` method. This is useful for loading the session with data before issuing a request to your application: - - withSession(['foo' => 'bar']) - ->visit('/'); - } - } - -Of course, one common use of the session is for maintaining state for the authenticated user. The `actingAs` helper method provides a simple way to authenticate a given user as the current user. For example, we may use a [model factory](#model-factories) to generate and authenticate a user: - - create(); - - $this->actingAs($user) - ->withSession(['foo' => 'bar']) - ->visit('/') - ->see('Hello, '.$user->name); - } - } - -You may also specify which guard should be used to authenticate the given user by passing the guard name as the second argument to the `actingAs` method: - - $this->actingAs($user, 'api') - - -### Disabling Middleware - -When testing your application, you may find it convenient to disable [middleware](/docs/{{version}}/middleware) for some of your tests. This will allow you to test your routes and controller in isolation from any middleware concerns. Laravel includes a simple `WithoutMiddleware` trait that you can use to automatically disable all middleware for the test class: - - withoutMiddleware(); - - $this->visit('/') - ->see('Laravel 5'); - } - } - - -### Custom HTTP Requests - -If you would like to make a custom HTTP request into your application and get the full `Illuminate\Http\Response` object, you may use the `call` method: - - public function testApplication() - { - $response = $this->call('GET', '/'); - - $this->assertEquals(200, $response->status()); - } - -If you are making `POST`, `PUT`, or `PATCH` requests you may pass an array of input data with the request. Of course, this data will be available in your routes and controller via the [Request instance](/docs/{{version}}/requests): - - $response = $this->call('POST', '/user', ['name' => 'Taylor']); - - -### PHPUnit Assertions - -Laravel provides a variety of custom assertion methods for [PHPUnit](https://phpunit.de/) tests: - -Method | Description -------------- | ------------- -`->assertResponseOk();` | Assert that the client response has an OK status code. -`->assertResponseStatus($code);` | Assert that the client response has a given code. -`->assertViewHas($key, $value = null);` | Assert that the response view has a given piece of bound data. -`->assertViewHasAll(array $bindings);` | Assert that the view has a given list of bound data. -`->assertViewMissing($key);` | Assert that the response view is missing a piece of bound data. -`->assertRedirectedTo($uri, $with = []);` | Assert whether the client was redirected to a given URI. -`->assertRedirectedToRoute($name, $parameters = [], $with = []);` | Assert whether the client was redirected to a given route. -`->assertRedirectedToAction($name, $parameters = [], $with = []);` | Assert whether the client was redirected to a given action. -`->assertSessionHas($key, $value = null);` | Assert that the session has a given value. -`->assertSessionHasAll(array $bindings);` | Assert that the session has a given list of values. -`->assertSessionHasErrors($bindings = [], $format = null);` | Assert that the session has errors bound. -`->assertHasOldInput();` | Assert that the session has old input. -`->assertSessionMissing($key);` | Assert that the session is missing a given key. diff --git a/artisan.md b/artisan.md index a910c6f..e5712f4 100644 --- a/artisan.md +++ b/artisan.md @@ -1,391 +1,39 @@ -# Console Commands +## Artisan CLI -- [Introduction](#introduction) -- [Writing Commands](#writing-commands) - - [Generating Commands](#generating-commands) - - [Command Structure](#command-structure) -- [Defining Input Expectations](#defining-input-expectations) - - [Arguments](#arguments) - - [Options](#options) - - [Input Arrays](#input-arrays) - - [Input Descriptions](#input-descriptions) -- [Command I/O](#command-io) - - [Retrieving Input](#retrieving-input) - - [Prompting For Input](#prompting-for-input) - - [Writing Output](#writing-output) -- [Registering Commands](#registering-commands) -- [Programatically Executing Commands](#programatically-executing-commands) - - [Calling Commands From Other Commands](#calling-commands-from-other-commands) +- [မိတ်ဆက်](#introduction) +- [အသုုံးပြုပုုံ](#အသုုံးပြုပုုံ) -## Introduction +## မိတ်ဆက် -Artisan is the command-line interface included with Laravel. It provides a number of helpful commands that can assist you while you build your application. To view a list of all available Artisan commands, you may use the `list` command: +Artisan သည် laravel တွင်အသုုံးပြုသည့် command line interface တစ်ခုုဖြစ်သည်။ ၄င်းတွင် application develop ပြုလုုပ်ရာတွင် အလွန်အသုုံးဝင်လှသော commands များစွာပါဝင်သည်။ ၄င်းမှာ Symfony ၏ console component မှဆင်းသက်လာခြင်း ဖြစ်သည်။ - php artisan list -Every command also includes a "help" screen which displays and describes the command's available arguments and options. To view a help screen, simply precede the name of the command with `help`: + +## အသုုံးပြုပုုံ - php artisan help migrate +#### အသုုံးပြုနုုိင်သည့် Command များကုုိ စီရီပြသခြင်း - -## Writing Commands +Artisan တွင်ပါဝင်သည့် Command အကုုန်လုုံးကုုိ list အနေဖြင့် ပြသလုုိပါက `list` ဟုုသည့် command ကုုိ အသုုံးပြုနုုိင်သည်။ -In addition to the commands provided with Artisan, you may also build your own custom commands. Commands are typically stored in the `app/Console/Commands` directory; however, you are free to choose your own storage location as long as your commands can be loaded by Composer. + php artisan list - -### Generating Commands +#### Command တစ်ခုုချင်း၏ အသုုံးပြုခြင်း လမ်းညွန်မှုကုုိ ကြည့်ရှုခြင်း -To create a new command, use the `make:command` Artisan command. This command will create a new command class in the `app/Console/Commands` directory. The generated command will include the default set of properties and methods that are present on all commands: +Command တုုိင်းလုုိလုုိ တွင် “help” ဟုု အပုုိဆောင်း ရုုိက်ခြင်း ဖြင့် မိမိတုုိ ့ အသုုံးပြုမည့် Command တွင် ထည့်သွင်းရမည့် arguments များနှင့် ရွေးချယ်စရာများကုုိ သိရှိနုုိင်ပါသည်။ - php artisan make:command SendEmails + php artisan help migrate - -### Command Structure +#### Configuration Environment ကုုိ သတ်မှတ်ခြင်း -After generating your command, you should fill in the `signature` and `description` properties of the class, which will be used when displaying your command on the `list` screen. The `handle` method will be called when your command is executed. You may place your command logic in this method. +မိမိတုုိ ့ အသုုံးပြုလုုိသည် Configuration Environment ကုုိ —env ဟုုသော switch ဖြင့် ရွေးချယ်သတ်မှတ်နုုိင်သည်။ -> {tip} For greater code reuse, it is good practice to keep your console commands light and let them defer to application services to accomplish their tasks. In the example below, note that we inject a service class to do the "heavy lifting" of sending the e-mails. -Let's take a look at an example command. Note that we are able to inject any dependencies we need into the command's constructor. The Laravel [service container](/docs/{{version}}/container) will automatically inject all dependencies type-hinted in the constructor: + php artisan migrate --env=local - drip = $drip; - } - - /** - * Execute the console command. - * - * @return mixed - */ - public function handle() - { - $this->drip->send(User::find($this->argument('user'))); - } - } - - -## Defining Input Expectations - -When writing console commands, it is common to gather input from the user through arguments or options. Laravel makes it very convenient to define the input you expect from the user using the `signature` property on your commands. The `signature` property allows you to define the name, arguments, and options for the command in a single, expressive, route-like syntax. - - -### Arguments - -All user supplied arguments and options are wrapped in curly braces. In the following example, the command defines one **required** argument: `user`: - - /** - * The name and signature of the console command. - * - * @var string - */ - protected $signature = 'email:send {user}'; - -You may also make arguments optional and define default values for arguments: - - // Optional argument... - email:send {user?} - - // Optional argument with default value... - email:send {user=foo} - - -### Options - -Options, like arguments, are another form of user input. Options are prefixed by two hyphens (`--`) when they are specified on the command line. There are two types of options: those that receive a value and those that don't. Options that don't receive a value serve as a boolean "switch". Let's take a look at an example of this type of option: - - /** - * The name and signature of the console command. - * - * @var string - */ - protected $signature = 'email:send {user} {--queue}'; - -In this example, the `--queue` switch may be specified when calling the Artisan command. If the `--queue` switch is passed, the value of the option will be `true`. Otherwise, the value will be `false`: - - php artisan email:send 1 --queue - - -#### Options With Values - -Next, let's take a look at an option that expects a value. If the user must specify a value for an option, suffix the option name with a `=` sign: - - /** - * The name and signature of the console command. - * - * @var string - */ - protected $signature = 'email:send {user} {--queue=}'; - -In this example, the user may pass a value for the option like so: - - php artisan email:send 1 --queue=default - -You may assign default values to options by specifying the default value after the option name. If no option value is passed by the user, the default value will be used: - - email:send {user} {--queue=default} - - -#### Option Shortcuts - -To assign a shortcut when defining an option, you may specify it before the option name and use a | delimiter to separate the shortcut from the full option name: - - email:send {user} {--Q|queue} - - -### Input Arrays - -If you would like to define arguments or options to expect array inputs, you may use the `*` character. First, let's take a look at an example that specifies an array argument: - - email:send {user*} - -When calling this method, the `user` arguments may be passed in order to the command line. For example, the following command will set the value of `user` to `['foo', 'bar']`: - - php artisan email:send foo bar - -When defining an option that expects an array input, each option value passed to the command should be prefixed with the option name: - - email:send {user} {--id=*} - - php artisan email:send --id=1 --id=2 - - -### Input Descriptions - -You may assign descriptions to input arguments and options by separating the parameter from the description using a colon. If you need a little extra room to define your command, feel free to spread the definition across multiple lines: - - /** - * The name and signature of the console command. - * - * @var string - */ - protected $signature = 'email:send - {user : The ID of the user} - {--queue= : Whether the job should be queued}'; - - -## Command I/O - - -### Retrieving Input - -While your command is executing, you will obviously need to access the values for the arguments and options accepted by your command. To do so, you may use the `argument` and `option` methods: - - /** - * Execute the console command. - * - * @return mixed - */ - public function handle() - { - $userId = $this->argument('user'); - - // - } - -If you need to retrieve all of the arguments as an `array`, call the `arguments` method: - - $arguments = $this->arguments(); - -Options may be retrieved just as easily as arguments using the `option` method. To retrieve all of the options as an array, call the `options` method: - - // Retrieve a specific option... - $queueName = $this->option('queue'); - - // Retrieve all options... - $options = $this->options(); - -If the argument or option does not exist, `null` will be returned. - - -### Prompting For Input - -In addition to displaying output, you may also ask the user to provide input during the execution of your command. The `ask` method will prompt the user with the given question, accept their input, and then return the user's input back to your command: - - /** - * Execute the console command. - * - * @return mixed - */ - public function handle() - { - $name = $this->ask('What is your name?'); - } - -The `secret` method is similar to `ask`, but the user's input will not be visible to them as they type in the console. This method is useful when asking for sensitive information such as a password: - - $password = $this->secret('What is the password?'); - -#### Asking For Confirmation - -If you need to ask the user for a simple confirmation, you may use the `confirm` method. By default, this method will return `false`. However, if the user enters `y` in response to the prompt, the method will return `true`. - - if ($this->confirm('Do you wish to continue? [y|N]')) { - // - } - -#### Auto-Completion - -The `anticipate` method can be used to provide auto-completion for possible choices. The user can still choose any answer, regardless of the auto-completion hints: - - $name = $this->anticipate('What is your name?', ['Taylor', 'Dayle']); - -#### Multiple Choice Questions - -If you need to give the user a predefined set of choices, you may use the `choice` method. You may set the default value to be returned if no option is chosen: - - $name = $this->choice('What is your name?', ['Taylor', 'Dayle'], $default); - - -### Writing Output - -To send output to the console, use the `line`, `info`, `comment`, `question` and `error` methods. Each of these methods will use appropriate ANSI colors for their purpose. For example, let's display some general information to the user. Typically, the `info` method will display in the console as green text: - - /** - * Execute the console command. - * - * @return mixed - */ - public function handle() - { - $this->info('Display this on the screen'); - } - -To display an error message, use the `error` method. Error message text is typically displayed in red: - - $this->error('Something went wrong!'); - -If you would like to display plain, uncolored console output, use the `line` method: - - $this->line('Display this on the screen'); - -#### Table Layouts - -The `table` method makes it easy to correctly format multiple rows / columns of data. Just pass in the headers and rows to the method. The width and height will be dynamically calculated based on the given data: - - $headers = ['Name', 'Email']; - - $users = App\User::all(['name', 'email'])->toArray(); - - $this->table($headers, $users); - -#### Progress Bars - -For long running tasks, it could be helpful to show a progress indicator. Using the output object, we can start, advance and stop the Progress Bar. First, define the total number of steps the process will iterate through. Then, advance the Progress Bar after processing each item: - - $users = App\User::all(); - - $bar = $this->output->createProgressBar(count($users)); - - foreach ($users as $user) { - $this->performTask($user); - - $bar->advance(); - } - - $bar->finish(); - -For more advanced options, check out the [Symfony Progress Bar component documentation](http://symfony.com/doc/2.7/components/console/helpers/progressbar.html). - - -## Registering Commands - -Once your command is finished, you need to register it with Artisan. All commands are registered in the `app/Console/Kernel.php` file. Within this file, you will find a list of commands in the `commands` property. To register your command, simply add the command's class name to the list. When Artisan boots, all the commands listed in this property will be resolved by the [service container](/docs/{{version}}/container) and registered with Artisan: - - protected $commands = [ - Commands\SendEmails::class - ]; - - -## Programatically Executing Commands - -Sometimes you may wish to execute an Artisan command outside of the CLI. For example, you may wish to fire an Artisan command from a route or controller. You may use the `call` method on the `Artisan` facade to accomplish this. The `call` method accepts the name of the command as the first argument, and an array of command parameters as the second argument. The exit code will be returned: - - Route::get('/foo', function () { - $exitCode = Artisan::call('email:send', [ - 'user' => 1, '--queue' => 'default' - ]); - - // - }); - -Using the `queue` method on the `Artisan` facade, you may even queue Artisan commands so they are processed in the background by your [queue workers](/docs/{{version}}/queues). Before using this method, make sure you have configured your queue and are running a queue listener: - - Route::get('/foo', function () { - Artisan::queue('email:send', [ - 'user' => 1, '--queue' => 'default' - ]); - - // - }); - -If you need to specify the value of an option that does not accept string values, such as the `--force` flag on the `migrate:refresh` command, you may pass `true` or `false`: - - $exitCode = Artisan::call('migrate:refresh', [ - '--force' => true, - ]); - - -### Calling Commands From Other Commands - -Sometimes you may wish to call other commands from an existing Artisan command. You may do so using the `call` method. This `call` method accepts the command name and an array of command parameters: - - /** - * Execute the console command. - * - * @return mixed - */ - public function handle() - { - $this->call('email:send', [ - 'user' => 1, '--queue' => 'default' - ]); - - // - } - -If you would like to call another console command and suppress all of its output, you may use the `callSilent` method. The `callSilent` method has the same signature as the `call` method: - - $this->callSilent('email:send', [ - 'user' => 1, '--queue' => 'default' - ]); + php artisan --version diff --git a/authentication.md b/authentication.md deleted file mode 100644 index 669621b..0000000 --- a/authentication.md +++ /dev/null @@ -1,502 +0,0 @@ -# Authentication - -- [Introduction](#introduction) - - [Database Considerations](#introduction-database-considerations) -- [Authentication Quickstart](#authentication-quickstart) - - [Routing](#included-routing) - - [Views](#included-views) - - [Authenticating](#included-authenticating) - - [Retrieving The Authenticated User](#retrieving-the-authenticated-user) - - [Protecting Routes](#protecting-routes) - - [Login Throttling](#login-throttling) -- [Manually Authenticating Users](#authenticating-users) - - [Remembering Users](#remembering-users) - - [Other Authentication Methods](#other-authentication-methods) -- [HTTP Basic Authentication](#http-basic-authentication) - - [Stateless HTTP Basic Authentication](#stateless-http-basic-authentication) -- [Adding Custom Guards](#adding-custom-guards) -- [Adding Custom User Providers](#adding-custom-user-providers) - - [The User Provider Contract](#the-user-provider-contract) - - [The Authenticatable Contract](#the-authenticatable-contract) -- [Events](#events) - - -## Introduction - -> {tip} **Want to get started fast?** Just run `php artisan make:auth` in a fresh Laravel application and navigate your browser to `http://your-app.dev/register` or any other URL that is assigned to your application. This single command will take care of scaffolding your entire authentication system! - -Laravel makes implementing authentication very simple. In fact, almost everything is configured for you out of the box. The authentication configuration file is located at `config/auth.php`, which contains several well documented options for tweaking the behavior of the authentication services. - -At its core, Laravel's authentication facilities are made up of "guards" and "providers". Guards define how users are authenticated for each request. For example, Laravel ships with a `session` guard which maintains state using session storage and cookies. - -Providers define how users are retrieved from your persistent storage. Laravel ships with support for retrieving users using Eloquent and the database query builder. However, you are free to define additional providers as needed for your application. - -Don't worry if this all sounds confusing now! Many applications will never need to modify the default authentication configuration. - - -### Database Considerations - -By default, Laravel includes an `App\User` [Eloquent model](/docs/{{version}}/eloquent) in your `app` directory. This model may be used with the default Eloquent authentication driver. If your application is not using Eloquent, you may use the `database` authentication driver which uses the Laravel query builder. - -When building the database schema for the `App\User` model, make sure the password column is at least 60 characters in length. Maintaining the default string column length of 255 characters would be a good choice. - -Also, you should verify that your `users` (or equivalent) table contains a nullable, string `remember_token` column of 100 characters. This column will be used to store a token for users that select the "remember me" option when logging into your application. - - -## Authentication Quickstart - -Laravel ships with several pre-built authentication controllers, which are located in the `App\Http\Controllers\Auth` namespace. The `RegisterController` handles new user registration, the `LoginController` handles authentication, the `ForgotPasswordController` handles e-mailing links for resetting passwords, and the `ResetPasswordController` contains the logic to reset passwords. Each of these controllers uses a trait to include their necessary methods. For many applications, you will not need to modify these controllers at all. - - -### Routing - -Laravel provides a quick way to scaffold all of the routes and views you need for authentication using one simple command: - - php artisan make:auth - -This command should be used on fresh applications and will install a layout view, registration and login views, as well as routes for all authentication end-points. A `HomeController` will also be generated to handle post-login requests to your application's dashboard. - - -### Views - -As mentioned in the previous section, the `php artisan make:auth` command will create all of the views you need for authentication and place them in the `resources/views/auth` directory. - -The `make:auth` command will also create a `resources/views/layouts` directory containing a base layout for your application. All of these views use the Bootstrap CSS framework, but you are free to customize them however you wish. - - -### Authenticating - -Now that you have routes and views setup for the included authentication controllers, you are ready to register and authenticate new users for your application! You may simply access your application in a browser since the authentication controllers already contain the logic (via their traits) to authenticate existing users and store new users in the database. - -#### Path Customization - -When a user is successfully authenticated, they will be redirected to the `/home` URI. You can customize the post-authentication redirect location by defining a `redirectTo` property on the `LoginController`, `RegisterController`, and `ResetPasswordController`: - - protected $redirectTo = '/'; - -When a user is not successfully authenticated, they will be automatically redirected back to the login form. - -#### Guard Customization - -You may also customize the "guard" that is used to authenticate and register users. To get started, define a `guard` method on your `LoginController`, `RegisterController`, and `ResetPasswordController`. The method should return a guard instance: - - use Illuminate\Support\Facades\Auth; - - protected function guard() - { - return Auth::guard('guard-name'); - } - -#### Validation / Storage Customization - -To modify the form fields that are required when a new user registers with your application, or to customize how new users are stored into your database, you may modify the `RegisterController` class. This class is responsible for validating and creating new users of your application. - -The `validator` method of the `RegisterController` contains the validation rules for new users of the application. You are free to modify this method as you wish. - -The `create` method of the `RegisterController` is responsible for creating new `App\User` records in your database using the [Eloquent ORM](/docs/{{version}}/eloquent). You are free to modify this method according to the needs of your database. - - -### Retrieving The Authenticated User - -You may access the authenticated user via the `Auth` facade: - - use Illuminate\Support\Facades\Auth; - - $user = Auth::user(); - -Alternatively, once a user is authenticated, you may access the authenticated user via an `Illuminate\Http\Request` instance. Remember, type-hinted classes will automatically be injected into your controller methods: - - user() returns an instance of the authenticated user... - } - } - -#### Determining If The Current User Is Authenticated - -To determine if the user is already logged into your application, you may use the `check` method on the `Auth` facade, which will return `true` if the user is authenticated: - - use Illuminate\Support\Facades\Auth; - - if (Auth::check()) { - // The user is logged in... - } - -> {tip} Even though it is possible to determine if a user is authenticated using the `check` method, you will typically use a middleware to verify that the user is authenticated before allowing the user access to certain routes / controllers. To learn more about this, check out the documentation on [protecting routes](/docs/{{version}}/authentication#protecting-routes). - - -### Protecting Routes - -[Route middleware](/docs/{{version}}/middleware) can be used to only allow authenticated users to access a given route. Laravel ships with an `auth` middleware, which is defined at `Illuminate\Auth\Middleware\Authenticate`. Since this middleware is already registered in your HTTP kernel, all you need to do is attach the middleware to a route definition: - - Route::get('profile', function() { - // Only authenticated users may enter... - })->middleware('auth'); - -Of course, if you are using [controllers](/docs/{{version}}/controllers), you may call the `middleware` method from the controller's constructor instead of attaching it in the route definition directly: - - public function __construct() - { - $this->middleware('auth'); - } - -#### Specifying A Guard - -When attaching the `auth` middleware to a route, you may also specify which guard should be used to authenticate the user. The guard specified should correspond to one of the keys in the `guards` array of your `auth.php` configuration file: - - public function __construct() - { - $this->middleware('auth:api'); - } - - -### Login Throttling - -If you are using Laravel's built-in `LoginController` class, the `Illuminate\Foundation\Auth\ThrottlesLogins` trait will already be included in your controller. By default, the user will not be able to login for one minute if they fail to provide the correct credentials after several attempts. The throttling is unique to the user's username / e-mail address and their IP address. - - -## Manually Authenticating Users - -Of course, you are not required to use the authentication controllers included with Laravel. If you choose to remove these controllers, you will need to manage user authentication using the Laravel authentication classes directly. Don't worry, it's a cinch! - -We will access Laravel's authentication services via the `Auth` [facade](/docs/{{version}}/facades), so we'll need to make sure to import the `Auth` facade at the top of the class. Next, let's check out the `attempt` method: - - $email, 'password' => $password])) { - // Authentication passed... - return redirect()->intended('dashboard'); - } - } - } - -The `attempt` method accepts an array of key / value pairs as its first argument. The values in the array will be used to find the user in your database table. So, in the example above, the user will be retrieved by the value of the `email` column. If the user is found, the hashed password stored in the database will be compared with the hashed `password` value passed to the method via the array. If the two hashed passwords match an authenticated session will be started for the user. - -The `attempt` method will return `true` if authentication was successful. Otherwise, `false` will be returned. - -The `intended` method on the redirector will redirect the user to the URL they were attempting to access before being intercepted by the authentication middleware. A fallback URI may be given to this method in case the intended destination is not available. - -#### Specifying Additional Conditions - -If you wish, you also may add extra conditions to the authentication query in addition to the user's e-mail and password. For example, we may verify that user is marked as "active": - - if (Auth::attempt(['email' => $email, 'password' => $password, 'active' => 1])) { - // The user is active, not suspended, and exists. - } - -> {note} In these examples, `email` is not a required option, it is merely used as an example. You should use whatever column name corresponds to a "username" in your database. - -#### Accessing Specific Guard Instances - -You may specify which guard instance you would like to utilize using the `guard` method on the `Auth` facade. This allows you to manage authentication for separate parts of your application using entirely separate authenticatable models or user tables. - -The guard name passed to the `guard` method should correspond to one of the guards configured in your `auth.php` configuration file: - - if (Auth::guard('admin')->attempt($credentials)) { - // - } - -#### Logging Out - -To log users out of your application, you may use the `logout` method on the `Auth` facade. This will clear the authentication information in the user's session: - - Auth::logout(); - - -### Remembering Users - -If you would like to provide "remember me" functionality in your application, you may pass a boolean value as the second argument to the `attempt` method, which will keep the user authenticated indefinitely, or until they manually logout. Of course, your `users` table must include the string `remember_token` column, which will be used to store the "remember me" token. - - if (Auth::attempt(['email' => $email, 'password' => $password], $remember)) { - // The user is being remembered... - } - -> {tip} If you are using the built-in `LoginController` that is shipped with Laravel, the proper logic to "remember" users is already implemented by the traits used by the controller. - -If you are "remembering" users, you may use the `viaRemember` method to determine if the user was authenticated using the "remember me" cookie: - - if (Auth::viaRemember()) { - // - } - - -### Other Authentication Methods - -#### Authenticate A User Instance - -If you need to log an existing user instance into your application, you may call the `login` method with the user instance. The given object must be an implementation of the `Illuminate\Contracts\Auth\Authenticatable` [contract](/docs/{{version}}/contracts). Of course, the `App\User` model included with Laravel already implements this interface: - - Auth::login($user); - - // Login and "remember" the given user... - Auth::login($user, true); - -Of course, you may specify the guard instance you would like to use: - - Auth::guard('admin')->login($user); - -#### Authenticate A User By ID - -To log a user into the application by their ID, you may use the `loginUsingId` method. This method simply accepts the primary key of the user you wish to authenticate: - - Auth::loginUsingId(1); - - // Login and "remember" the given user... - Auth::loginUsingId(1, true); - -#### Authenticate A User Once - -You may use the `once` method to log a user into the application for a single request. No sessions or cookies will be utilized, which means this method may be helpful when building a stateless API. The `once` method has the same signature as the `attempt` method: - - if (Auth::once($credentials)) { - // - } - - -## HTTP Basic Authentication - -[HTTP Basic Authentication](http://en.wikipedia.org/wiki/Basic_access_authentication) provides a quick way to authenticate users of your application without setting up a dedicated "login" page. To get started, attach the `auth.basic` [middleware](/docs/{{version}}/middleware) to your route. The `auth.basic` middleware is included with the Laravel framework, so you do not need to define it: - - Route::get('profile', function() { - // Only authenticated users may enter... - })->middleware('auth.basic'); - -Once the middleware has been attached to the route, you will automatically be prompted for credentials when accessing the route in your browser. By default, the `auth.basic` middleware will use the `email` column on the user record as the "username". - -#### A Note On FastCGI - -If you are using PHP FastCGI, HTTP Basic authentication may not work correctly out of the box. The following lines should be added to your `.htaccess` file: - - RewriteCond %{HTTP:Authorization} ^(.+)$ - RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] - - -### Stateless HTTP Basic Authentication - -You may also use HTTP Basic Authentication without setting a user identifier cookie in the session, which is particularly useful for API authentication. To do so, [define a middleware](/docs/{{version}}/middleware) that calls the `onceBasic` method. If no response is returned by the `onceBasic` method, the request may be passed further into the application: - - middleware('auth.basic.once'); - - -## Adding Custom Guards - -You may define your own authentication guards using the `extend` method on the `Auth` facade. You should place this call to `provider` within a [service provider](/docs/{{version}}/providers). Since Laravel already ships with an `AuthServiceProvider`, we can place the code in that provider: - - registerPolicies(); - - Auth::extend('jwt', function($app, $name, array $config) { - // Return an instance of Illuminate\Contracts\Auth\Guard... - - return new JwtGuard(Auth::createUserProvider($config['provider'])); - }); - } - } - -As you can see in the example above, the callback passed to the `extend` method should return an implementation of `Illuminate\Contracts\Auth\Guard`. This interface contains a few methods you will need to implement to define a custom guard. Once your custom guard has been defined, you may use the guard in the `guards` configuration of your `auth.php` configuration file: - - 'guards' => [ - 'api' => [ - 'driver' => 'jwt', - 'provider' => 'users', - ], - ], - - -## Adding Custom User Providers - -If you are not using a traditional relational database to store your users, you will need to extend Laravel with your own authentication user provider. We will use the `provider` method on the `Auth` facade to define a custom user provider: - - registerPolicies(); - - Auth::provider('riak', function($app, array $config) { - // Return an instance of Illuminate\Contracts\Auth\UserProvider... - - return new RiakUserProvider($app->make('riak.connection')); - }); - } - } - -After you have registered the provider using the `provider` method, you may switch to the new user provider in your `auth.php` configuration file. First, define a `provider` that uses your new driver: - - 'providers' => [ - 'users' => [ - 'driver' => 'riak', - ], - ], - -Finally, you may use this provider in your `guards` configuration: - - 'guards' => [ - 'web' => [ - 'driver' => 'session', - 'provider' => 'users', - ], - ], - - -### The User Provider Contract - -The `Illuminate\Contracts\Auth\UserProvider` implementations are only responsible for fetching a `Illuminate\Contracts\Auth\Authenticatable` implementation out of a persistent storage system, such as MySQL, Riak, etc. These two interfaces allow the Laravel authentication mechanisms to continue functioning regardless of how the user data is stored or what type of class is used to represent it. - -Let's take a look at the `Illuminate\Contracts\Auth\UserProvider` contract: - - getAuthPassword()` to the value of `$credentials['password']`. This method should return `true` or `false` indicating on whether the password is valid. - - -### The Authenticatable Contract - -Now that we have explored each of the methods on the `UserProvider`, let's take a look at the `Authenticatable` contract. Remember, the provider should return implementations of this interface from the `retrieveById` and `retrieveByCredentials` methods: - - -## Events - -Laravel raises a variety of [events](/docs/{{version}}/events) during the authentication process. You may attach listeners to these events in your `EventServiceProvider`: - - /** - * The event listener mappings for the application. - * - * @var array - */ - protected $listen = [ - 'Illuminate\Auth\Events\Attempting' => [ - 'App\Listeners\LogAuthenticationAttempt', - ], - - 'Illuminate\Auth\Events\Login' => [ - 'App\Listeners\LogSuccessfulLogin', - ], - - 'Illuminate\Auth\Events\Logout' => [ - 'App\Listeners\LogSuccessfulLogout', - ], - - 'Illuminate\Auth\Events\Lockout' => [ - 'App\Listeners\LogLockout', - ], - ]; diff --git a/authorization.md b/authorization.md deleted file mode 100644 index ca0ee91..0000000 --- a/authorization.md +++ /dev/null @@ -1,314 +0,0 @@ -# Authorization - -- [Introduction](#introduction) -- [Gates](#gates) - - [Writing Gates](#writing-gates) - - [Authorizing Actions](#authorizing-actions-via-gates) -- [Creating Policies](#creating-policies) - - [Generating Policies](#generating-policies) - - [Registering Policies](#registering-policies) -- [Writing Policies](#writing-policies) - - [Policy Methods](#policy-methods) - - [Methods Without Models](#methods-without-models) - - [Policy Filters](#policy-filters) -- [Authorizing Actions Using Policies](#authorizing-actions-using-policies) - - [Via The User Model](#via-the-user-model) - - [Via Middleware](#via-middleware) - - [Via Controller Helpers](#via-controller-helpers) - - [Via Blade Templates](#via-blade-templates) - - -## Introduction - -In addition to providing [authentication](/docs/{{version}}/authentication) services out of the box, Laravel also provides a simple way to authorize user actions against a given resource. Like authentication, Laravel's approach to authorization is simple, and there are two primary ways of authorizing actions: gates and policies. - -Think of gates and policies like routes and controllers. Gates provide a simple, Closure based approach to authorization while policies, like controllers, group their logic around a particular model or resource. We'll explore gates first and then examine policies. - -It is important to not view gates and policies as mutually exclusive for your application. Most applications will most likely contain a mixture of gates and policies, and that is perfectly fine! Gates are most applicable to actions which are not related to any model or resource, such as viewing an administrator dashboard. In contrast, policies should be used when you wish to authorize an action for a particular model or resource. - - -## Gates - -### Writing Gates - -Gates are Closures that determine if a user is authorized to perform a given action and are typically defined in the `App\Providers\AuthServiceProvider` class using the `Gate` facade. Gates always receive a user instance as their first argument, and may optionally receive additional arguments such as a relevant Eloquent model: - - /** - * Register any authentication / authorization services. - * - * @return void - */ - public function boot() - { - $this->registerPolicies(); - - Gate::define('update-post', function ($user, $post) { - return $user->id == $post->user_id; - }); - } - - -### Authorizing Actions - -To authorize an action using gates, you should use the `allows` method. Note that you are not required to pass the currently authenticated user to the `allows` method. Laravel will automatically take care of passing the user into the gate Closure: - - if (Gate::allows('update-post', $post)) { - // The current user can update the post... - }); - -If you would like to determine if a particular user is authorized to perform an action, you may use the `forUser` method on the `Gate` facade: - - if (Gate::forUser($user)->allows('update-post', $post)) { - // The user can update the post... - } - - -## Creating Policies - - -### Generating Policies - -Policies are classes that organize authorization logic around a particular model or resource. For example, if your application is a blog, you may have a `Post` model and a corresponding `PostPolicy` to authorize user actions such as creating or updating posts. - -You may generate a policy using the `make:policy` [artisan command](/docs/{{version}}/artisan). The generated policy will be placed in the `app/Policies` directory. If this directory does not exist in your application, Laravel will create it for you: - - php artisan make:policy PostPolicy - -The `make:policy` command will generate an empty policy class. If you would like to generate a class with the basic "CRUD" policy methods already included in the class, you may specify a `--model` when executing the command: - - php artisan make:policy PostPolicy --model=Post - -> {tip} All policies are resolved via the Laravel [service container](/docs/{{version}}/container), allowing you to type-hint any needed dependencies in the policy's constructor to have them automatically injected. - - -### Registering Policies - -Once the policy exists, it needs to be registered. The `AuthServiceProvider` included with fresh Laravel applications contains a `policies` property which maps your Eloquent models to their corresponding policies. Registering a policy will instruct Laravel which policy to utilize when authorizing actions against a given model: - - PostPolicy::class, - ]; - - /** - * Register any application authentication / authorization services. - * - * @return void - */ - public function boot() - { - $this->registerPolicies(); - - // - } - } - - -## Writing Policies - - -### Policy Methods - -Once the policy has been registered, you may add methods for each action it authorizes. For example, let's define an `update` method on our `PostPolicy` which determines if a given `User` can update a given `Post` instance. - -The `update` method will receive a `User` and a `Post` instance as its arguments, and should return `true` or `false` indicating whether the user is authorized to update the given `Post`. So, for this example, let's verify that the user's `id` matches the `user_id` on the post: - - id === $post->user_id; - } - } - -You may continue to define additional methods on the policy as needed for the various actions it authorizes. For example, you might define `view` or `delete` methods to authorize various `Post` actions, but remember you are free to give your policy methods any name you like. - -> {tip} If you used the `--model` option when generating your policy via the Artisan console, it will already contain methods for the `view`, `create`, `update`, and `delete` actions. - - -### Methods Without Models - -Some policy methods only receive the currently authenticated user and not an instance of the model they authorize. This situation is most common when authorizing `create` actions. For example, if you are creating a blog, you may wish to check if a user is authorized to create any posts at all. - -When defining policy methods that will not receive a model instance, such as a `create` method, it will not receive a model instance. Instead, you should define the method as only expecting the authenticated user: - - /** - * Determine if the given user can create posts. - * - * @param \App\User $user - * @return bool - */ - public function create(User $user) - { - // - } - -> {tip} If you used the `--model` option when generating your policy, all of the relevant "CRUD" policy methods will already be defined on the generated policy. - - -### Policy Filters - -For certain users, you may wish to authorize all actions within a given policy. To accomplish this, define a `before` method on the policy. The `before` method will be executed before any other methods on the policy, giving you an opportunity to authorize the action before the intended policy method is actually called. This feature is most commonly used for authorizing application administrators to perform any action: - - public function before($user, $ability) - { - if ($user->isSuperAdmin()) { - return true; - } - } - - -## Authorizing Actions Using Policies - - -### Via The User Model - -The `User` model that is included with your Laravel application includes two helpful methods for authorizing actions: `can` and `cant`. The `can` method receives the action you wish to authorize and the relevant model. For example, let's determine if a user is authorized to update a given `Post` model: - - if ($user->can('update', $post)) { - // - } - -If a [policy is registered](#registering-policies) for the given model, the `can` method will automatically call the appropriate policy and return the boolean result. If no policy is registered for the model, the `can` method will attempt to call the Closure based Gate matching the given action name. - -#### Actions That Don't Require Models - -Remember, some actions like `create` may not require a model instance. In these situations, you may pass a class name to the `can` method. The class name will be used to determine which policy to use when authorizing the action: - - use App\Post; - - if ($user->can('create', Post::class)) { - // Executes the "create" method on the relevant policy... - } - - -### Via Middleware - -Laravel includes a middleware that can authorize actions before the incoming request even reaches your routes or controllers. By default, the `Illuminate\Auth\Middleware\Authorize` middleware is assigned the `can` key in your `App\Http\Kernel` class. Let's explore an example of using the `can` middleware to authorize that a user can update a blog post: - - use App\Post; - - Route::put('/post/{post}', function (Post $post) { - // The current user may update the post... - })->middleware('can:update,post'); - -In this example, we're passing the `can` middleware two arguments. The first is the name of the action we wish to authorize and the second is the route parameter we wish to pass to the policy method. In this case, since we are using [implicit model binding](/docs/{{version}}/routing#implicit-binding), a `Post` model will be passed to the policy method. If the user is not authorized to perform the given action, a HTTP response with a `403` status code will be generated by the middleware. - -#### Actions That Don't Require Models - -Again, some actions like `create` may not require a model instance. In these situations, you may pass a class name to the middleware. The class name will be used to determine which policy to use when authorizing the action: - - Route::post('/post', function () { - // The current user may create posts... - })->middleware('can:create,App\Post'); - - -### Via Controller Helpers - -In addition to helpful methods provided to the `User` model, Laravel provides a helpful `authorize` method to any of your controllers which extend the `App\Http\Controllers\Controller` base class. Like the `can` method, this method accepts the name of the action you wish to authorize and the relevant model. If the action is not authorized, the `authorize` method will throw an `Illuminate\Auth\Access\AuthorizationException`, which the default Laravel exception handler will convert to an HTTP response with a `403` status code: - - authorize('update', $post); - - // The current user can update the blog post... - } - } - -#### Actions That Don't Require Models - -As previously discussed, some actions like `create` may not require a model instance. In these situations, you may pass a class name to the `authorize` method. The class name will be used to determine which policy to use when authorizing the action: - - /** - * Create a new blog post. - * - * @param Request $request - * @return Response - */ - public function create(Request $request) - { - $this->authorize('create', Post::class); - - // The current user can create blog posts... - } - - -### Via Blade Templates - -When writing Blade templates, you may wish to display a portion of the page only if the user is authorized to perform a given action. For example, you may wish to show an update form for a blog post only if the user can actually update the post. In this situation, you may use the `@can` and `@cannot` directives. - - @can('update', $post) - - @endcan - - @cannot('update', $post) - - @endcannot - -These directives are convenient short-cuts for writing `@if` and `@unless` statements. The `@can` and `@cannot` statements above respectively translate to the following statements: - - @if (Auth::user()->can('update', $post)) - - @endif - - @unless (Auth::user()->can('update', $post)) - - @endunless - -#### Actions That Don't Require Models - -Like most of the other authorization methods, you may pass a class name to the `@can` and `@cannot` directives if the action does not require a model instance: - - @can('create', Post::class) - - @endcan - - @cannot('create', Post::class) - - @endcannot diff --git a/billing.md b/billing.md index 5388cd0..05cf532 100644 --- a/billing.md +++ b/billing.md @@ -2,622 +2,230 @@ - [Introduction](#introduction) - [Configuration](#configuration) - - [Stripe](#stripe-configuration) - - [Braintree](#braintree-configuration) - - [Currency Configuration](#currency-configuration) -- [Subscriptions](#subscriptions) - - [Creating Subscriptions](#creating-subscriptions) - - [Checking Subscription Status](#checking-subscription-status) - - [Changing Plans](#changing-plans) - - [Subscription Quantity](#subscription-quantity) - - [Subscription Taxes](#subscription-taxes) - - [Cancelling Subscriptions](#cancelling-subscriptions) - - [Resuming Subscriptions](#resuming-subscriptions) - - [Updating Credit Cards](#updating-credit-cards) -- [Subscription Trials](#subscription-trials) - - [With Credit Card Up Front](#with-credit-card-up-front) - - [Without Credit Card Up Front](#without-credit-card-up-front) -- [Handling Stripe Webhooks](#handling-stripe-webhooks) - - [Defining Webhook Event Handlers](#defining-webhook-event-handlers) - - [Failed Subscriptions](#handling-failed-subscriptions) -- [Handling Braintree Webhooks](#handling-braintree-webhooks) - - [Defining Webhook Event Handlers](#defining-braintree-webhook-event-handlers) - - [Failed Subscriptions](#handling-braintree-failed-subscriptions) -- [Single Charges](#single-charges) +- [Subscribing To A Plan](#subscribing-to-a-plan) +- [No Card Up Front](#no-card-up-front) +- [Swapping Subscriptions](#swapping-subscriptions) +- [Subscription Quantity](#subscription-quantity) +- [Cancelling A Subscription](#cancelling-a-subscription) +- [Resuming A Subscription](#resuming-a-subscription) +- [Checking Subscription Status](#checking-subscription-status) +- [Handling Failed Payments](#handling-failed-payments) - [Invoices](#invoices) - - [Generating Invoice PDFs](#generating-invoice-pdfs) ## Introduction -Laravel Cashier provides an expressive, fluent interface to [Stripe's](https://stripe.com) and [Braintree's](https://braintreepayments.com) subscription billing services. It handles almost all of the boilerplate subscription billing code you are dreading writing. In addition to basic subscription management, Cashier can handle coupons, swapping subscription, subscription "quantities", cancellation grace periods, and even generate invoice PDFs. - -> {note} If you're only performing "one-off" charges and do not offer subscriptions. You should not use Cashier. You should use the Stripe and Braintree SDKs directly. +Laravel Cashier က Subscription Billing Service တစ်ခုဖြစ်တဲ့ Stripe သုံးတဲ့အခါ ပိုပြီးလွယ်ကူစေအောင်လို့ လုပ်ပေးထားပါတယ်။ Stripe သုံးဖို့အတွက် အစအဆုံး ပြန်ရေးနေစရာမလိုတော့အောင်လို့ အခြေခံ Code တွေ ရေးထားပြီးသားဖြစ်ပါတယ်။ အခြေခံ Subscription Management အပြင် , Coupons, Subscription ကို Upgrade လုပ်တဲ့ Feature (Swap), Subscription Quantities, Subscription ကို သတ်မှတ်ထားတဲ့ ကာလအတွင်း Subscription ကို Cancel လုပ်လို့ရမယ့် Feature လည်းပါဝင်ပါတယ်။ နောက် Invoice ကို PDF ထုတ်လို့ရအောင်လဲ ကူညီပေးပါတယ်။ ## Configuration - -### Stripe - #### Composer -First, add the Cashier package for Stripe to your `composer.json` file and run the `composer update` command: +ပထမဆုံး သင့်ရဲ့ Composer File မှာ Casher package ကိုထည့်ပေးပါ၊ - "laravel/cashier": "~6.0" + "laravel/cashier": "~2.0" #### Service Provider -Next, register the `Laravel\Cashier\CashierServiceProvider` [service provider](/docs/{{version}}/providers) in your `config/app.php` configuration file. - -#### Database Migrations - -Before using Cashier, we'll also need to [prepare the database](/docs/{{version}}/migrations). We need to add several columns to your `users` table and create a new `subscriptions` table to hold all of our customer's subscriptions: - - Schema::table('users', function ($table) { - $table->string('stripe_id')->nullable(); - $table->string('card_brand')->nullable(); - $table->string('card_last_four')->nullable(); - $table->timestamp('trial_ends_at')->nullable(); - }); - - Schema::create('subscriptions', function ($table) { - $table->increments('id'); - $table->integer('user_id'); - $table->string('name'); - $table->string('stripe_id'); - $table->string('stripe_plan'); - $table->integer('quantity'); - $table->timestamp('trial_ends_at')->nullable(); - $table->timestamp('ends_at')->nullable(); - $table->timestamps(); - }); - -Once the migrations have been created, run the `migrate` Artisan command. - -#### Billable Model +နောက်... သင်ရဲ့ `app` configuration file ထဲမှာ `Laravel\Cashier\CashierServiceProvider` ကို regiter လုပ်ပါ၊ -Next, add the `Billable` trait to your model definition. This trait provides various methods to allow you to perform common billing tasks, such as creating subscriptions, applying coupons, and updating credit card information: +#### Migration - use Laravel\Cashier\Billable; +Chashier ကိုမသုံးခင်မှာ... columns တစ်ချို့ကို သင့်ရဲ့ database ထဲကို add လုပ်ဖို့လိုပါမယ်။ မစိုးရိမ်ပါနဲ့... လိုအပ်တဲ့ column တွေကိုထက်ထည့်ဖို့ `cashier:table` Artisan command ကိုသုံးနိုင်ပါတယ်။ - class User extends Authenticatable - { - use Billable; - } +#### Model Setup -#### API Keys +နောက်... သင့်ရဲ့ model definition မှာ BillableTrait နဲ့ appropriate date mutators တွေကို add လိုက်ပါ: -Finally, you should configure your Stripe key in your `services.php` configuration file. You can retrieve your Stripe API keys from the Stripe control panel: + use Laravel\Cashier\BillableTrait; + use Laravel\Cashier\BillableInterface; - 'stripe' => [ - 'model' => App\User::class, - 'secret' => env('STRIPE_SECRET'), - ], + class User extends Eloquent implements BillableInterface { - -### Braintree + use BillableTrait; -#### Braintree Caveats - -For many operations, the Stripe and Braintree implementations of Cashier function the same. Both services provide subscription billing with credit cards but Braintree also supports payments via PayPal. However, Braintree also lacks some features that are supported by Stripe. You should keep the following in mind when deciding to use Stripe or Braintree: - -
-- Braintree supports PayPal while Stripe does not. -- Braintree does not support the `increment` and `decrement` methods on subscriptions. This is a Braintree limitation, not a Cashier limitation. -- Braintree does not support percentage based discounts. This is a Braintree limitation, not a Cashier limitation. -
- -#### Composer - -First, add the Cashier package for Braintree to your `composer.json` file and run the `composer update` command: - - "laravel/cashier-braintree": "~1.0" - -#### Service Provider + protected $dates = ['trial_ends_at', 'subscription_ends_at']; -Next, register the `Laravel\Cashier\CashierServiceProvider` [service provider](/docs/{{version}}/providers) in your `config/app.php` configuration file. + } -#### Plan Credit Coupon +#### Stripe Key -Before using Cashier with Braintree, you will need to define a `plan-credit` discount in your Braintree control panel. This discount will be used to properly prorate subscriptions that change from yearly to monthly billing, or from monthly to yearly billing. +နောက်ဆုံးမှာတော့ သင့်ရဲ့ Stripe key ကိုသင့်ရဲ့ bootstrap files တစ်ခုထဲမှာ set လုပ်လိုက်ပါ -The discount amount configured in the Braintree control panel can be any value you wish, as Cashier will simply override the defined amount with our own custom amount each time we apply the coupon. This coupon is needed since Braintree does not natively support prorating subscriptions across subscription frequencies. + User::setStripeKey('stripe-key'); -#### Database Migrations + +## Subscribing To A Plan -Before using Cashier, we'll need to [prepare the database](/docs/{{version}}/migrations). We need to add several columns to your `users` table and create a new `subscriptions` table to hold all of our customer's subscriptions: +user ကို Stripe plan တစ်ခုပေးဖို့ သင့်မှာ model instance တစ်ခုရှိတယ်ဆိုရင် လွယ်လွယ်ကူကူ subscribe လုပ်နိုင်ပါတယ် + $user = User::find(1); - Schema::table('users', function ($table) { - $table->string('braintree_id')->nullable(); - $table->string('paypal_email')->nullable(); - $table->string('card_brand')->nullable(); - $table->string('card_last_four')->nullable(); - $table->timestamp('trial_ends_at')->nullable(); - }); + $user->subscription('monthly')->create($creditCardToken); - Schema::create('subscriptions', function ($table) { - $table->increments('id'); - $table->integer('user_id'); - $table->string('name'); - $table->string('braintree_id'); - $table->string('braintree_plan'); - $table->integer('quantity'); - $table->timestamp('trial_ends_at')->nullable(); - $table->timestamp('ends_at')->nullable(); - $table->timestamps(); - }); +subscription ကို create လုပ်ပြီးသွားပြီဆိုရင် သင့်အနေနဲ့ cupon ကို apply လုပ်ဖို့ `withCoupon` ကိုသုံးနိုင်ပါတယ် -Once the migrations have been created, simply run the `migrate` Artisan command. + $user->subscription('monthly') + ->withCoupon('code') + ->create($creditCardToken); -#### Billable Model +Stripe subscription ကို `subscription` method က automatically create လုပ်သွားလိမ့်မယ်... သင့်ရဲ့ Strip customer ID နဲ့ အခြား billing information နဲ့ပတ်သတ်တဲ့ database တွေကော update လုပ်သွားပါလိမ့်မယ်။ -Next, add the `Billable` trait to your model definition: +သင့်မှာ trail period ရှိတယ်ဆိုရင် သင့်ရဲ့ model မှာ trial end date ကို subscribing လုပ်ပြီးမှာ set လုပ်ထားရဲ့လားဆိုတာကိုသေချာ make sure လုပ်ပါ။ - use Laravel\Cashier\Billable; + $user->trial_ends_at = Carbon::now()->addDays(14); - class User extends Authenticatable - { - use Billable; - } + $user->save(); -#### API Keys + +## No Card Up Front +သင့်ရဲ့ application က ပထမဆုံး free-trial တစ်ခုကို credit-card မပါဘဲ လက်ခံမယ်ဆိုရင် `cardUpFront` ကိုသင့်ရဲ့ modle မှာ `false` ဆိုပြီး set လုပ်ပါ... -Next, You should configure the following options in your `services.php` file: + protected $cardUpFront = false; - 'braintree' => [ - 'model' => App\User::class, - 'environment' => env('BRAINTREE_ENV'), - 'merchant_id' => env('BRAINTREE_MERCHANT_ID'), - 'public_key' => env('BRAINTREE_PUBLIC_KEY'), - 'private_key' => env('BRAINTREE_PRIVATE_KEY'), - ], +Account creation မှာ trial နောက်ဆုံးရက်ကို model မှာ set လုပ်ထားရဲ့လားဆိုတာကို make sure လုပ်ပါ... -Then you should add the following Braintree SDK calls to your `AppServiceProvider` service provider's `boot` method: + $user->trial_ends_at = Carbon::now()->addDays(14); - \Braintree_Configuration::environment(env('BRAINTREE_ENV')); - \Braintree_Configuration::merchantId(env('BRAINTREE_MERCHANT_ID')); - \Braintree_Configuration::publicKey(env('BRAINTREE_PUBLIC_KEY')); - \Braintree_Configuration::privateKey(env('BRAINTREE_PRIVATE_KEY')); + $user->save(); - -### Currency Configuration + +## Swapping Subscriptions -The default Cashier currency is United States Dollars (USD). You can change the default currency by calling the `Cashier::useCurrency` method from within the `boot` method of one of your service providers. The `useCurrency` method accepts two string parameters: the currency and the currency's symbol: +Subscription အသစ်တစ်ခုမှာ user တစ်ယောက် ကို swap လုပ်ချင်တယ်ဆိုရင် `swap` method ကိုသုံးပါ... - use Laravel\Cashier\Cashier; + $user->subscription('premium')->swap(); - Cashier::useCurrency('eur', '€'); - - -## Subscriptions - - -### Creating Subscriptions - -To create a subscription, first retrieve an instance of your billable model, which typically will be an instance of `App\User`. Once you have retrieved the model instance, you may use the `newSubscription` method to create the model's subscription: - - $user = User::find(1); - - $user->newSubscription('main', 'monthly')->create($creditCardToken); - -The first argument passed to the `newSubscription` method should be the name of the subscription. If your application only offers a single subscription, you might call this `main` or `primary`. The second argument is the specific Stripe / Braintree plan the user is subscribing to. This value should correspond to the plan's identifier in Stripe or Braintree. - -The `create` method will begin the subscription as well as update your database with the customer ID and other relevant billing information. - -#### Additional User Details - -If you would like to specify additional customer details, you may do so by passing them as the second argument to the `create` method: - - $user->newSubscription('main', 'monthly')->create($creditCardToken, [ - 'email' => $email, - ]); - -To learn more about the additional fields supported by Stripe or Braintree, check out Stripe's [documentation on customer creation](https://stripe.com/docs/api#create_customer) or the corresponding [Braintree documentation](https://developers.braintreepayments.com/reference/request/customer/create/php). - -#### Coupons - -If you would like to apply a coupon when creating the subscription, you may use the `withCoupon` method: - - $user->newSubscription('main', 'monthly') - ->withCoupon('code') - ->create($creditCardToken); - - -### Checking Subscription Status - -Once a user is subscribed to your application, you may easily check their subscription status using a variety of convenient methods. First, the `subscribed` method returns `true` if the user has an active subscription, even if the subscription is currently within its trial period: - - if ($user->subscribed('main')) { - // - } - -The `subscribed` method also makes a great candidate for a [route middleware](/docs/{{version}}/middleware), allowing you to filter access to routes and controllers based on the user's subscription status: - - public function handle($request, Closure $next) - { - if ($request->user() && ! $request->user()->subscribed('main')) { - // This user is not a paying customer... - return redirect('billing'); - } - - return $next($request); - } - -If you would like to determine if a user is still within their trial period, you may use the `onTrial` method. This method can be useful for displaying a warning to the user that they are still on their trial period: - - if ($user->subscription('main')->onTrial()) { - // - } - -The `subscribedToPlan` method may be used to determine if the user is subscribed to a given plan based on a given Stripe / Braintree plan ID. In this example, we will determine if the user's `main` subscription is actively subscribed to the `monthly` plan: - - if ($user->subscribedToPlan('monthly', 'main')) { - // - } - -#### Cancelled Subscription Status - -To determine if the user was once an active subscriber, but has cancelled their subscription, you may use the `cancelled` method: - - if ($user->subscription('main')->cancelled()) { - // - } - -You may also determine if a user has cancelled their subscription, but are still on their "grace period" until the subscription fully expires. For example, if a user cancels a subscription on March 5th that was originally scheduled to expire on March 10th, the user is on their "grace period" until March 10th. Note that the `subscribed` method still returns `true` during this time: - - if ($user->subscription('main')->onGracePeriod()) { - // - } - - -### Changing Plans - -After a user is subscribed to your application, they may occasionally want to change to a new subscription plan. To swap a user to a new subscription, pass the plan's identifier to the `swap` method: - - $user = App\User::find(1); - - $user->subscription('main')->swap('provider-plan-id'); - -If the user is on trial, the trial period will be maintained. Also, if a "quantity" exists for the subscription, that quantity will also be maintained. - -If you would like to swap plans and cancel any trial period the user is currently on, you may use the `skipTrial` method: - - $user->subscription('main') - ->skipTrial() - ->swap('provider-plan-id'); +တကယ်လို့ user က trial မှာဘဲရှိနေတယ် ဆိုရင် trial က ပုံမှန် maintained လုပ်သွားပါ့မယ်။ နောက် subscription အတွက် "quantity" တစ်ခုရှိတယ်ဆိုရင် အဲ့ဒီ့ quantity ကိုလည်း maintain လုပ်သွားပါ့မယ်။ -### Subscription Quantity - -> {note} Subscription quantities are only supported by the Stripe edition of Cashier. Braintree does not have a feature that corresponds to Stripe's "quantity". - -Sometimes subscriptions are affected by "quantity". For example, your application might charge $10 per month **per user** on an account. To easily increment or decrement your subscription quantity, use the `incrementQuantity` and `decrementQuantity` methods: - - $user = User::find(1); - - $user->subscription('main')->incrementQuantity(); - - // Add five to the subscription's current quantity... - $user->subscription('main')->incrementQuantity(5); - - $user->subscription('main')->decrementQuantity(); - - // Subtract five to the subscription's current quantity... - $user->subscription('main')->decrementQuantity(5); - -Alternatively, you may set a specific quantity using the `updateQuantity` method: +## Subscription Quantity - $user->subscription('main')->updateQuantity(10); +တစ်ခါတစ်လေမှာ subscriptions တွေက "quantity" ကနေပြီးတော့ affect ဖြစ်တယ်။ ဥပမာ... သင့်ရဲ့ application က user account တစ်ခုအတွက် တစ်လ ကို $10 charge လုပ်တယ်ဆိုပါတော့။ သင့်ရဲ့ subscription quantity ကို တိုးချင်တာဘဲဖြစ်ဖြစ်၊ လျော့ချင်တာဘဲဖြစ်ဖြစ် လွယ်လွယ်ကူကူ လုပ်ချင်တယ်ဆိုရင် `increment` နဲ့ `decrement` methods ကိုသုံးနိုင်ပါတယ် -For more information on subscription quantities, consult the [Stripe documentation](https://stripe.com/docs/guides/subscriptions#setting-quantities). + $user = User::find(1); - -### Subscription Taxes + $user->subscription()->increment(); -To specify the tax percentage a user pays on a subscription, implement the `taxPercentage` method on your billable model, and return a numeric value between 0 and 100, with no more than 2 decimal places. + // Add five to the subscription's current quantity... + $user->subscription()->increment(5) - public function taxPercentage() { - return 20; - } + $user->subscription->decrement(); -The `taxPercentage` method enables you to apply a tax rate on a model-by-model basis, which may be helpful for a user base that spans multiple countries and tax rates. + // Subtract five to the subscription's current quantity... + $user->subscription()->decrement(5) -> {note} The `taxPercentage` method only applies to subscription charges. If you use Cashier to make "one off" charges, you will need to manually specify the tax rate at that time. + +## Cancelling A Subscription - -### Cancelling Subscriptions +Subscription တစ်ခုကို Cancel လုပ်တာ ပန်ခြံထဲမှာ လမ်းလျှောက်ရသလိုပါဘဲ... -To cancel a subscription, simply call the `cancel` method on the user's subscription: + $user->subscription()->cancel(); - $user->subscription('main')->cancel(); +Subscription တစ်ခု cancel လုပ်သွားတဲ့အချိန်မှာ Casher က `subscription_ends_at` column ကို သင့်ရဲ့ database မှာ အလိုလို set လုပ်သွားပါ့မယ်။ ဥပမာ၊ customer က March လတစ်ရက်နေ့မှာ subscription ကို Cancel လုပ်သွားတယ် နောက် March 5 ရက်နေ့မှာ subscription end ဖြစ်မယ်လို့ schedule လည်းမရှိဘူးဆိုရင် `subscribed` method က March လ 5 ရက်နေ့အထိ return `true` ပြန်နေမှာပါ။ -When a subscription is cancelled, Cashier will automatically set the `ends_at` column in your database. This column is used to know when the `subscribed` method should begin returning `false`. For example, if a customer cancels a subscription on March 1st, but the subscription was not scheduled to end until March 5th, the `subscribed` method will continue to return `true` until March 5th. + +## Resuming A Subscription -You may determine if a user has cancelled their subscription but are still on their "grace period" using the `onGracePeriod` method: +User တစ်ယောက်ကသူရဲ့ subscription ကို cancelled လုပ်သွားတဲ့အချိန်မှာ သင့်အနေနဲ့ သူတို့ resume ပြန်လုပ်ဖို့ဆုတောင်းနေမှာပေါ့၊ ဒါဆိုရင် `resume` method ကိုသုံးလိုက်ပါ: - if ($user->subscription('main')->onGracePeriod()) { - // - } + $user->subscription('monthly')->resume($creditCardToken); -If you wish to cancel a subscription immediately, call the `cancelNow` method on the user's subscription: +တကယ်လို့ user က subscription တစ်ခုကို cancels လုပ်လိုက်တယ်၊ နောက် subscription က fully expired မဖြစ်ခင်မှာ user က resume ပြန်လုပ်လိုက်တယ်ဆိုရင် သူတို့က bill တွေကိုချက်ချင်းမဖြတ်ပါဘူး။ သူတို့ရဲ့ subscription တွေကို ရိုးရှင်းစွာပဲ re-activated လုပ်သွားပါတယ် နောက် သူတို့ရဲ့ မူလ billing cycle အတိုင်း billed လုပ်ပါလိမ့်မယ်။ - $user->subscription('main')->cancelNow(); - - -### Resuming Subscriptions - -If a user has cancelled their subscription and you wish to resume it, use the `resume` method. The user **must** still be on their grace period in order to resume a subscription: - - $user->subscription('main')->resume(); - -If the user cancels a subscription and then resumes that subscription before the subscription has fully expired, they will not be billed immediately. Instead, their subscription will simply be re-activated, and they will be billed on the original billing cycle. - - -### Updating Credit Cards - -The `updateCard` method may be used to update a customer's credit card information. This method accepts a Stripe token and will assign the new credit card as the default billing source: - - $user->updateCard($creditCardToken); - - -## Subscription Trials - - -### With Credit Card Up Front - -If you would like to offer trial periods to your customers while still collecting payment method information up front, You should use the `trialDays` method when creating your subscriptions: - - $user = User::find(1); - - $user->newSubscription('main', 'monthly') - ->trialDays(10) - ->create($creditCardToken); - -This method will set the trial period ending date on the subscription record within the database, as well as instruct Stripe / Braintree to not begin billing the customer until after this date. - -> {note} If the customer's subscription is not cancelled before the trial ending date they will be charged as soon as the trial expires, so you should be sure to notify your users of their trial ending date. - -You may determine if the user is within their trial period using either the `onTrial` method of the user instance, or the `onTrial` method of the subscription instance. The two examples below are identical: - - if ($user->onTrial('main')) { - // - } - - if ($user->subscription('main')->onTrial()) { - // - } - - -### Without Credit Card Up Front - -If you would like to offer trial periods without collecting the user's payment method information up front, you may simply set the `trial_ends_at` column on the user record to your desired trial ending date. This is typically done during user registration: - - $user = User::create([ - // Populate other user properties... - 'trial_ends_at' => Carbon::now()->addDays(10), - ]); - -Cashier refers to this type of trial as a "generic trial", since it is not attached to any existing subscription. The `onTrial` method on the `User` instance will return `true` if the current date is not past the value of `trial_ends_at`: - - if ($user->onTrial()) { - // User is within their trial period... - } - -You may also use the `onGenericTrial` method if you wish to know specifically that the user is within their "generic" trial period and has not created an actual subscription yet: - - if ($user->onGenericTrial()) { - // User is within their "generic" trial period... - } - -Once you are ready to create an actual subscription for the user, you may use the `newSubscription` method as usual: - - $user = User::find(1); - - $user->newSubscription('main', 'monthly')->create($creditCardToken); - - -## Handling Stripe Webhooks - -Both Stripe and Braintree can notify your application of a variety of events via webhooks. To handle Stripe webhooks, define a route that points to Cashier's webhook controller. This controller will handle all incoming webhook requests and dispatch them to the proper controller method: - - Route::post( - 'stripe/webhook', - '\Laravel\Cashier\Http\Controllers\WebhookController@handleWebhook' - ); - -> {note} Once you have registered your route, be sure to configure the webhook URL in your Stripe control panel settings. - -By default, this controller will automatically handle cancelling subscriptions that have too many failed charges (as defined by your Stripe settings); however, as we'll soon discover, you can extend this controller to handle any webhook event you like. - -#### Webhooks & CSRF Protection - -Since Stripe webhooks need to bypass Laravel's [CSRF protection](/docs/{{version}}/routing#csrf-protection), be sure to list the URI as an exception in your `VerifyCsrfToken` middleware or list the route outside of the `web` middleware group: - - protected $except = [ - 'stripe/*', - ]; - - -### Defining Webhook Event Handlers - -Cashier automatically handles subscription cancellation on failed charges, but if you have additional Stripe webhook events you would like to handle, simply extend the Webhook controller. Your method names should correspond to Cashier's expected convention, specifically, methods should be prefixed with `handle` and the "camel case" name of the Stripe webhook you wish to handle. For example, if you wish to handle the `invoice.payment_succeeded` webhook, you should add a `handleInvoicePaymentSucceeded` method to the controller: - - -### Failed Subscriptions - -What if a customer's credit card expires? No worries - the Cashier webhook controller that can easily cancel the customer's subscription for you. As noted above, all you need to do is point a route to the controller: - - Route::post( - 'stripe/webhook', - '\Laravel\Cashier\Http\Controllers\WebhookController@handleWebhook' - ); - -That's it! Failed payments will be captured and handled by the controller. The controller will cancel the customer's subscription when Stripe determines the subscription has failed (normally after three failed payment attempts). - - -## Handling Braintree Webhooks - -Both Stripe and Braintree can notify your application of a variety of events via webhooks. To handle Braintree webhooks, define a route that points to Cashier's webhook controller. This controller will handle all incoming webhook requests and dispatch them to the proper controller method: - - Route::post( - 'stripe/webhook', - '\Laravel\Cashier\Http\Controllers\WebhookController@handleWebhook' - ); - -> {note} Once you have registered your route, be sure to configure the webhook URL in your Braintree control panel settings. - -By default, this controller will automatically handle cancelling subscriptions that have too many failed charges (as defined by your Braintree settings); however, as we'll soon discover, you can extend this controller to handle any webhook event you like. - -#### Webhooks & CSRF Protection - -Since Braintree webhooks need to bypass Laravel's [CSRF protection](/docs/{{version}}/routing#csrf-protection), be sure to list the URI as an exception in your `VerifyCsrfToken` middleware or list the route outside of the `web` middleware group: - - protected $except = [ - 'stripe/*', - ]; - - -### Defining Webhook Event Handlers - -Cashier automatically handles subscription cancellation on failed charges, but if you have additional Braintree webhook events you would like to handle, simply extend the Webhook controller. Your method names should correspond to Cashier's expected convention, specifically, methods should be prefixed with `handle` and the "camel case" name of the Braintree webhook you wish to handle. For example, if you wish to handle the `dispute_opened` webhook, you should add a `handleDisputeOpened` method to the controller: - - +## Checking Subscription Status - namespace App\Http\Controllers; +User တစ်ယောက်က သင့်ရဲ့ application ကို subscribed လုပ်သွားတာကို verify လုပ်ရန်အတွက် `subscribed` command: ကိုသုံးပါ- - use Braintree\WebhookNotification; - use Laravel\Cashier\Http\Controllers\WebhookController as CashierController; + if ($user->subscribed()) + { + // + } - class WebhookController extends CashierController - { - /** - * Handle a Braintree webhook. - * - * @param WebhookNotification $webhook - * @return Response - */ - public function handleDisputeOpened(WebhookNotification $notification) - { - // Handle The Event - } - } +`subscribed` method က Route filter အတွက် အကောင်းဆုံး အသင့်တော်ဆုံး လုပ်ဆောင်ပေးထားပါတယ်: - -### Failed Subscriptions -What if a customer's credit card expires? No worries - Cashier includes a Webhook controller that can easily cancel the customer's subscription for you. Just point a route to the controller: + Route::filter('subscribed', function() + { + if (Auth::user() && ! Auth::user()->subscribed()) + { + return Redirect::to('billing'); + } + }); - Route::post( - 'braintree/webhook', - '\Laravel\Cashier\Http\Controllers\WebhookController@handleWebhook' - ); +သင့်အနေနဲ့ user က trial ကာလမှာဟုတ်မဟုတ်ကို `onTrial` method ကိုအသုံးပြုပြီးတော့ ဆုံးဖြတ်ပေးနိုင်ပါတယ်: -That's it! Failed payments will be captured and handled by the controller. The controller will cancel the customer's subscription when Braintree determines the subscription has failed (normally after three failed payment attempts). Don't forget: you will need to configure the webhook URI in your Braintree control panel settings. + if ($user->onTrial()) + { + // + } - -## Single Charges +သင့်အနေနဲ့ user က active subscriber လား ဒါမှမဟုတ် cancel လုပ်လိုက်ပြီလားဆိုတာကို `cancelled` method ကိုသုံးပြီးတော့စစ်နိုင်ပါတယ်: -### Simple Charge -> {note} When using Stripe, the `charge` method accepts the amount you would like to charge in the **lowest denominator of the currency used by your application**. However, when using Braintree, you should pass the full dollar amount to the `charge` method: + if ($user->cancelled()) + { + // + } -If you would like to make a "one off" charge against a subscribed customer's credit card, you may use the `charge` method on a billable model instance. +သင့်အနေနဲ့ User ကသူ့ရဲ့ subscription ကို cancel လုပ်လိုက်ပြီ ဒါပေမယ့် subscription ကလည်း fully expires မဖြစ်သေးဘူး... တစ်နည်းအားဖြင့် "grace period" လည်းမကုန်သေးဘူးဆိုတာကို ဆုံးဖြတ်နိုင်ပါတယ်။ ဥပမာ၊ user က subscription ကို March လ 5 ရက်နေ့မှာ cancel လုပ်လိုက်တယ်... တကယ်တမ်း scheduled မှာက March လ 10 ရက်နေ့မှပြီးမယ်ဆိုရင် အဲ့ဒီ့ user က "grace period" မှာဘဲရှိသေးပါတယ်။ မှတ်ထားရမှာက `subscribed` method ကအဲ့ဒီ့အချိန်မှာ `true` return ဘဲပြန်နေဦးမှာပါ။ - // Stripe Accepts Charges In Cents... - $user->charge(100); + if ($user->onGracePeriod()) + { + // + } - // Braintree Accepts Charges In Dollars... - $user->charge(1); +User က သင့် application ရဲ့ plan တစ်ခုကိုအမြဲတမ်း subscribed လုပ်ပြီးပြီလား မလုပ်ရသေးဘူးလားဆိုတာကို `everSubscribed` method နဲ့ စစ်ဆေးနိုင်ပါတယ်: -The `charge` method accepts an array as its second argument, allowing you to pass any options you wish to the underlying Stripe / Braintree charge creation. Consult the Stripe or Braintree documentation regarding the options available to you when creating charges: + if ($user->everSubscribed()) + { + // + } - $user->charge(100, [ - 'custom_option' => $value, - ]); + +## Handling Failed Payments -The `charge` method will throw an exception if the charge fails. If the charge is successful, the full Stripe / Braintree response will be returned from the method: +ကတယ်လို့ customer ရဲ့ credit card expires ဖြစ်နေရင်လား၊ မစိုးရိမ်ပါနဲ့ Cashuer က Webhook controller တစ်ခုပါဝင်ပါတယ်... အဲဒါကဘာလုပ်နိုင်လဲဆိုရင် customer ရဲ့ subscriotion ကို သင့်အတွက် cancel လုပ်ပေးပါလိမ့်မယ်: - try { - $response = $user->charge(100); - } catch (Exception $e) { - // - } + Route::post('stripe/webhook', 'Laravel\Cashier\WebhookController@handleWebhook'); -### Charge With Invoice +ဒါဘဲလေ။ Payment Fail ဖြစ်တာတွေ capture လုပ်တာတွေကိုလည်း controller ကဖြေရှင်းပေးပါလိမ့်မယ်။ controller က payment သုံးကြိမ်ကြိုးစားလို့မှမရဘူးဆိုရင် customer subscription ကို cancel လုပ်ပါလိမ့်မယ်။ ဒီဥပမာမှာ `stripe/webbhook` URI က ဥပမာအတွက်ပါ။ သင့်အနေနဲ့အဲ့ဒီ့ URI ကို Stripe Setting မှာ configure လုပ်ဖို့လိုမှာပါ။ -Sometimes you may need to make a one-time charge but also generate an invoice for the charge so that you may offer a PDF receipt to your customer. The `invoiceFor` method lets you do just that. For example, let's invoice the customer $5.00 for a "One Time Fee": +သင်ထက်ပေါင်းထည့်ထားတဲ့ Stripe webhook event ကိုဖြေရှင်းချင်တယ်ဆိုရင် Webhook controller ကို ရိုးရှင်းစွာဘဲ extend လုပ်လိုက်ပါ : - // Stripe Accepts Charges In Cents... - $user->invoiceFor('One Time Fee', 500); + class WebhookController extends Laravel\Cashier\WebhookController { - // Braintree Accepts Charges In Dollars... - $user->invoiceFor('One Time Fee', 5); + public function handleWebhook() + { + // Handle other events... -The invoice will be charged immediately against the user's credit card. The `invoiceFor` method also accepts an array as its third argument, allowing you to pass any options you wish to the underlying Stripe / Braintree charge creation: + // Fallback to failed payment check... + return parent::handleWebhook(); + } - $user->invoiceFor('One Time Fee', 500, [ - 'custom-option' => $value, - ]); + } -> {note} The `invoiceFor` method will create a Stripe invoice which will retry failed billing attempts. If you do not want invoices to retry failed charges, you will need to close them using the Stripe API after the first failed charge. +> **Note:** In addition to updating the subscription information in your database, the Webhook controller will also cancel the subscription via the Stripe API. ## Invoices -You may easily retrieve an array of a billable model's invoices using the `invoices` method: - - $invoices = $user->invoices(); - - // Include pending invoices in the results... - $invoices = $user->invoicesIncludingPending(); - -When listing the invoices for the customer, you may use the invoice's helper methods to display the relevant invoice information. For example, you may wish to list every invoice in a table, allowing the user to easily download any of them: +သင့်အနေနဲ့ user invoices ရဲ့ array ကို `invoices` method ကိုသုံးပြီးတော့ လွယ်လွယ်ကူကူ retrieve လုပ်နိုင်ပါတယ်: - - @foreach ($invoices as $invoice) - - - - - - @endforeach -
{{ $invoice->date()->toFormattedDateString() }}{{ $invoice->total() }}Download
+ $invoices = $user->invoices(); - -### Generating Invoice PDFs +Customer တွေရဲ့ invoices တွေကို List လုပ်တဲ့အချိန်မှာ သင့်အနေနဲ့ invoice information နဲ့ပတ်သတ်တာတွေကို ပြသဖို့ရာအတွက် ဒီ helper တွေကို သုံးနိုင်ပါတယ်: -Before generating invoice PDFs, you need to install the `dompdf` PHP library: + {{ $invoice->id }} - composer require dompdf/dompdf + {{ $invoice->dateString() }} -Then, from within a route or controller, use the `downloadInvoice` method to generate a PDF download of the invoice. This method will automatically generate the proper HTTP response to send the download to the browser: + {{ $invoice->dollars() }} - use Illuminate\Http\Request; +Invoice PDF download ကို generate ထုတ်ဖို့ရာအတွက် `downloadInvoice` method ကိုသုံးပါ။ ဟုတ်တယ်...ဒါကတကယ်ကိုလွယ်ပါတယ်: - Route::get('user/invoice/{invoice}', function (Request $request, $invoiceId) { - return $request->user()->downloadInvoice($invoiceId, [ - 'vendor' => 'Your Company', - 'product' => 'Your Product', - ]); - }); + return $user->downloadInvoice($invoice->id, [ + 'vendor' => 'Your Company', + 'product' => 'Your Product', + ]); \ No newline at end of file diff --git a/blade.md b/blade.md deleted file mode 100644 index 0ae3537..0000000 --- a/blade.md +++ /dev/null @@ -1,366 +0,0 @@ -# Blade Templates - -- [Introduction](#introduction) -- [Template Inheritance](#template-inheritance) - - [Defining A Layout](#defining-a-layout) - - [Extending A Layout](#extending-a-layout) -- [Displaying Data](#displaying-data) - - [Blade & JavaScript Frameworks](#blade-and-javascript-frameworks) -- [Control Structures](#control-structures) - - [If Statements](#if-statements) - - [Loops](#loops) - - [The Loop Variable](#the-loop-variable) - - [Comments](#comments) -- [Including Sub-Views](#including-sub-views) - - [Rendering Views For Collections](#rendering-views-for-collections) -- [Stacks](#stacks) -- [Service Injection](#service-injection) -- [Extending Blade](#extending-blade) - - -## Introduction - -Blade is the simple, yet powerful templating engine provided with Laravel. Unlike other popular PHP templating engines, Blade does not restrict you from using plain PHP code in your views. In fact, all Blade views are compiled into plain PHP code and cached until they are modified, meaning Blade adds essentially zero overhead to your application. Blade view files use the `.blade.php` file extension and are typically stored in the `resources/views` directory. - - -## Template Inheritance - - -### Defining A Layout - -Two of the primary benefits of using Blade are _template inheritance_ and _sections_. To get started, let's take a look at a simple example. First, we will examine a "master" page layout. Since most web applications maintain the same general layout across various pages, it's convenient to define this layout as a single Blade view: - - - - - - App Name - @yield('title') - - - @section('sidebar') - This is the master sidebar. - @show - -
- @yield('content') -
- - - -As you can see, this file contains typical HTML mark-up. However, take note of the `@section` and `@yield` directives. The `@section` directive, as the name implies, defines a section of content, while the `@yield` directive is used to display the contents of a given section. - -Now that we have defined a layout for our application, let's define a child page that inherits the layout. - - -### Extending A Layout - -When defining a child view, use the Blade `@extends` directive to specify which layout the child view should "inherit". Views which extend a Blade layout may inject content into the layout's sections using `@section` directives. Remember, as seen in the example above, the contents of these sections will be displayed in the layout using `@yield`: - - - - @extends('layouts.app') - - @section('title', 'Page Title') - - @section('sidebar') - @@parent - -

This is appended to the master sidebar.

- @endsection - - @section('content') -

This is my body content.

- @endsection - -In this example, the `sidebar` section is utilizing the `@@parent` directive to append (rather than overwriting) content to the layout's sidebar. The `@@parent` directive will be replaced by the content of the layout when the view is rendered. - -Blade views may be returned from routes using the global `view` helper: - - Route::get('blade', function () { - return view('child'); - }); - - -## Displaying Data - -You may display data passed to your Blade views by wrapping the variable in curly braces. For example, given the following route: - - Route::get('greeting', function () { - return view('welcome', ['name' => 'Samantha']); - }); - -You may display the contents of the `name` variable like so: - - Hello, {{ $name }}. - -Of course, you are not limited to displaying the contents of the variables passed to the view. You may also echo the results of any PHP function. In fact, you can put any PHP code you wish inside of a Blade echo statement: - - The current UNIX timestamp is {{ time() }}. - -> {note} Blade `{{ }}` statements are automatically sent through PHP's `htmlentities` function to prevent XSS attacks. - -#### Echoing Data If It Exists - -Sometimes you may wish to echo a variable, but you aren't sure if the variable has been set. We can express this in verbose PHP code like so: - - {{ isset($name) ? $name : 'Default' }} - -However, instead of writing a ternary statement, Blade provides you with the following convenient short-cut, which will be compiled to the ternary statement above: - - {{ $name or 'Default' }} - -In this example, if the `$name` variable exists, its value will be displayed. However, if it does not exist, the word `Default` will be displayed. - -#### Displaying Unescaped Data - -By default, Blade `{{ }}` statements are automatically sent through PHP's `htmlentities` function to prevent XSS attacks. If you do not want your data to be escaped, you may use the following syntax: - - Hello, {!! $name !!}. - -> {note} Be very careful when echoing content that is supplied by users of your application. Always use the escaped, double curly brace syntax to prevent XSS attacks when displaying user supplied data. - - -### Blade & JavaScript Frameworks - -Since many JavaScript frameworks also use "curly" braces to indicate a given expression should be displayed in the browser, you may use the `@` symbol to inform the Blade rendering engine an expression should remain untouched. For example: - -

Laravel

- - Hello, @{{ name }}. - -In this example, the `@` symbol will be removed by Blade; however, `{{ name }}` expression will remain untouched by the Blade engine, allowing it to instead be rendered by your JavaScript framework. - -#### The `@verbatim` Directive - -If you are displaying JavaScript variables in a large portion of your template, you may wrap the HTML in the `@verbatim` directive so that you do not have to prefix each Blade echo statement with an `@` symbol: - - @verbatim -
- Hello, {{ name }}. -
- @endverbatim - - -## Control Structures - -In addition to template inheritance and displaying data, Blade also provides convenient short-cuts for common PHP control structures, such as conditional statements and loops. These short-cuts provide a very clean, terse way of working with PHP control structures, while also remaining familiar to their PHP counterparts. - - -### If Statements - -You may construct `if` statements using the `@if`, `@elseif`, `@else`, and `@endif` directives. These directives function identically to their PHP counterparts: - - @if (count($records) === 1) - I have one record! - @elseif (count($records) > 1) - I have multiple records! - @else - I don't have any records! - @endif - -For convenience, Blade also provides an `@unless` directive: - - @unless (Auth::check()) - You are not signed in. - @endunless - - -### Loops - -In addition to conditional statements, Blade provides simple directives for working with PHP's loop structures. Again, each of these directives functions identically to their PHP counterparts: - - @for ($i = 0; $i < 10; $i++) - The current value is {{ $i }} - @endfor - - @foreach ($users as $user) -

This is user {{ $user->id }}

- @endforeach - - @forelse ($users as $user) -
  • {{ $user->name }}
  • - @empty -

    No users

    - @endforelse - - @while (true) -

    I'm looping forever.

    - @endwhile - -> {tip} When looping, you may use the [loop variable](#the-loop-variable) to gain valuable information about the loop, such as whether you are in the first or last iteration through the loop. - -When using loops you may also end the loop or skip the current iteration: - - @foreach ($users as $user) - @if ($user->type == 1) - @continue - @endif - -
  • {{ $user->name }}
  • - - @if ($user->number == 5) - @break - @endif - @endforeach - -You may also include the condition with the directive declaration in one line: - - @foreach ($users as $user) - @continue($user->type == 1) - -
  • {{ $user->name }}
  • - - @break($user->number == 5) - @endforeach - - -### The Loop Variable - -When looping, a `$loop` variable will be available inside of your loop. This variable provides access to some useful bits of information such as the current loop index and whether this is the first or last iteration through the loop: - - @foreach ($users as $user) - @if ($loop->first) - This is the first iteration. - @endif - - @if ($loop->last) - This is the last iteration. - @endif - -

    This is user {{ $user->id }}

    - @endforeach - -If you are in a nested loop, you may access the parent loop's `$loop` variable via the `parent` property: - - @foreach ($users as $user) - @foreach ($user->posts as $post) - @if ($loop->parent->first) - This is first iteration of the parent loop. - @endif - @endforeach - @endforeach - -The `$loop` variable also contains a variety of other useful properties: - -Property | Description -------------- | ------------- -`$loop->index` | The index of the current loop iteration (starts at 0). -`$loop->iteration` | The current loop iteration (starts at 1). -`$loop->remaining` | The iteration remaining in the loop. -`$loop->count` | The total number of items in the array being iterated. -`$loop->first` | Whether this is the first iteration through the loop. -`$loop->last` | Whether this is the last iteration through the loop. -`$loop->depth` | The nesting level of the current loop. -`$loop->parent` | When in a nested loop, the parent's loop variable. - - -### Comments - -Blade also allows you to define comments in your views. However, unlike HTML comments, Blade comments are not included in the HTML returned by your application: - - {{-- This comment will not be present in the rendered HTML --}} - - -## Including Sub-Views - -Blade's `@include` directive allows you to include a Blade view from within another view. All variables that are available to the parent view will be made available to the included view: - -
    - @include('shared.errors') - -
    - -
    -
    - -Even though the included view will inherit all data available in the parent view, you may also pass an array of extra data to the included view: - - @include('view.name', ['some' => 'data']) - -> {note} You should avoid using the `__DIR__` and `__FILE__` constants in your Blade views, since they will refer to the location of the cached, compiled view. - - -### Rendering Views For Collections - -You may combine loops and includes into one line with Blade's `@each` directive: - - @each('view.name', $jobs, 'job') - -The first argument is the view partial to render for each element in the array or collection. The second argument is the array or collection you wish to iterate over, while the third argument is the variable name that will be assigned to the current iteration within the view. So, for example, if you are iterating over an array of `jobs`, typically you will want to access each job as a `job` variable within your view partial. The key for the current iteration will be available as the `key` variable within your view partial. - -You may also pass a fourth argument to the `@each` directive. This argument determines the view that will be rendered if the given array is empty. - - @each('view.name', $jobs, 'job', 'view.empty') - - -## Stacks - -Blade allows you to push to named stacks which can be rendered somewhere else in another view or layout. This can be particularly useful for specifying any JavaScript libraries required by your child views: - - @push('scripts') - - @endpush - -You may push to a stack as many times as needed. To render the complete stack contents, pass the name of the stack to the `@stack` directive: - - - - - @stack('scripts') - - - -## Service Injection - -The `@inject` directive may be used to retrieve a service from the Laravel [service container](/docs/{{version}}/container). The first argument passed to `@inject` is the name of the variable the service will be placed into, while the second argument is the class or interface name of the service you wish to resolve: - - @inject('metrics', 'App\Services\MetricsService') - -
    - Monthly Revenue: {{ $metrics->monthlyRevenue() }}. -
    - - -## Extending Blade - -Blade allows you to define your own custom directives using the `directive` method. When the Blade compiler encounters the custom directive, it will call the provided callback with the expression that the directive contains. - -The following example creates a `@datetime($var)` directive which formats a given `$var`, which should be an instance of `DateTime`: - - format('m/d/Y H:i'); ?>"; - }); - } - - /** - * Register bindings in the container. - * - * @return void - */ - public function register() - { - // - } - } - -As you can see, we will chain the `format` method onto whatever expression is passed into the directive. So, in this example, the final PHP generated by this directive will be: - - format('m/d/Y H:i'); ?> - -> {note} After updating the logic of a Blade directive, you will need to delete all of the cached Blade views. The cached Blade views may be removed using the `view:clear` Artisan command. diff --git a/broadcasting.md b/broadcasting.md deleted file mode 100644 index 01d92ab..0000000 --- a/broadcasting.md +++ /dev/null @@ -1,455 +0,0 @@ -# Event Broadcasting - -- [Introduction](#introduction) - - [Configuration](#configuration) - - [Driver Prerequisites](#driver-prerequisites) -- [Concept Overview](#concept-overview) - - [Using Example Application](#using-example-application) -- [Defining Broadcast Events](#defining-broadcast-events) - - [Broadcast Data](#broadcast-data) - - [Broadcast Queue](#broadcast-queue) -- [Authorizing Channels](#authorizing-channels) - - [Defining Authorization Routes](#defining-authorization-routes) - - [Defining Authorization Callbacks](#defining-authorization-callbacks) -- [Broadcasting Events](#broadcasting-events) - - [Only To Others](#only-to-others) -- [Receiving Broadcasts](#receiving-broadcasts) - - [Installing Laravel Echo](#installing-laravel-echo) - - [Listening For Events](#listening-for-events) - - [Namespaces](#namespaces) -- [Presence Channels](#presence-channels) - - [Authorizing Presence Channels](#authorizing-presence-channels) - - [Joining Presence Channels](#joining-presence-channels) - - [Broadcasting To Presence Channels](#broadcasting-to-presence-channels) -- [Notifications](#notifications) - - -## Introduction - -In many modern web applications, WebSockets are used to implement real-time, live-updating user interfaces. When some data is updated on the server, a message is typically sent over a WebSocket connection to be handled by the client. This provides a more robust, efficient alternative to continually polling your application for changes. - -To assist you in building these types of applications, Laravel makes it easy to "broadcast" your [events](/docs/{{version}}/events) over a WebSocket connection. Broadcasting your Laravel events allows you to share the same event names between your server-side code and your client-side JavaScript application. - -> {tip} Before diving into event broadcasting, make sure you have read all of the documentation regarding Laravel [events and listeners](/docs/{{version}}/events). - - -### Configuration - -All of your application's event broadcasting configuration is stored in the `config/broadcasting.php` configuration file. Laravel supports several broadcast drivers out of the box: [Pusher](https://pusher.com), [Redis](/docs/{{version}}/redis), and a `log` driver for local development and debugging. Additionally, a `null` driver is included which allows you to totally disable broadcasting. A configuration example is included for each of these drivers in the `config/broadcasting.php` configuration file. - -#### Broadcast Service Provider - -Before broadcasting any events, you will first need to register the `App\Providers\BroadcastServiceProvider`. In fresh Laravel applications, you only need to uncomment this provider in the `providers` array of your `config/app.php` configuration file. This provider will allow you to register the broadcast authorization routes and callbacks. - -#### CSRF Token - -[Laravel Echo](#installing-laravel-echo) will need access to the current session's CSRF token. If available, Echo will pull the token from the `Laravel.csrfToken` JavaScript object. This object is defined in the `resources/views/layouts/app.blade.php` layout that is created if you run the `make:auth` Artisan command. If you are not using this layout, you may define a `meta` tag in your application's `head` HTML element: - - - - -### Driver Prerequisites - -#### Pusher - -If you are broadcasting your events over [Pusher](https://pusher.com), you should install the Pusher PHP SDK using the Composer package manager: - - composer require pusher/pusher-php-server - -Next, you should configure your Pusher credentials in the `config/broadcasting.php` configuration file. An example Pusher configuration is already included in this file, allowing you to quickly specify your Pusher key, secret, and application ID. - -When using Pusher and [Laravel Echo](#installing-laravel-echo), you should specify `pusher` as your desired broadcaster when instantiating an Echo instance: - - import Echo from "laravel-echo" - - window.Echo = new Echo({ - broadcaster: 'pusher', - key: 'your-pusher-key' - }); - -#### Redis - -If you are using the Redis broadcaster, you should install the Predis library: - - composer require predis/predis - -The Redis broadcaster will broadcast messages using Redis' pub / sub feature; however, you will need to pair this with a WebSocket server that can receive the messages from Redis and broadcast them to your WebSocket channels. - -When the Redis broadcaster publishes an event, it will be published on the event's specified channel names and the payload will be a JSON encoded string containing the event name, a `data` payload, and the user that generated the event's socket ID (if applicable). - -#### Socket.IO - -> {note} Socket.IO server support is currently in beta and is community driven. Public and private channels are supported; however, presence channels are not fully implemented. - -If you are going to pair the Redis broadcaster with a Socket.IO server, you will need to include the Socket.IO JavaScript client library in your application's `head` HTML element: - - - -Next, you will need to instantiate Echo with the `socket.io` connector and a `host`. For example, if your application and socket server are running on the `app.dev` domain you should instantiate Echo like so: - - import Echo from "laravel-echo" - - window.Echo = new Echo({ - broadcaster: 'socket.io', - host: 'http://app.dev:6001' - }); - -Finally, you will need to run a compatible Socket.IO server. Laravel does not include a Socket.IO server implementation; however, a community driven Socket.IO server is currently maintained at the [tlaverdure/laravel-echo-server](https://github.com/tlaverdure/laravel-echo-server) GitHub repository. - -#### Queue Prerequisites - -Before broadcasting events, you will also need to configure and run a [queue listener](/docs/{{version}}/queues). All event broadcasting is done via queued jobs so that the response time of your application is not seriously affected. - - -## Concept Overview - -Laravel's event broadcasting allows you to broadcast your server-side Laravel events to your client-side JavaScript application using a driver-based approach to WebSockets. Currently, Laravel ships with [Pusher](http://pusher.com) and Redis drivers. The events may be easily consumed on the client-side using the [Laravel Echo](#installing-laravel-echo) Javascript package. - -Events are broadcast over "channels", which may be specified as public or private. Any visitor to your application may subscribe to a public channel without any authentication or authorization; however, in order to subscribe to a private channel, a user must be authenticated and authorized to listen on that channel. - - -### Using Example Application - -Before diving into each component of event broadcasting, let's take a high level overview using an e-commerce store as an example. We won't discuss the details of configuring [Pusher](http://pusher.com) or [Laravel Echo](#echo) since that will be discussed in detail in other sections of this documentation. - -In our application, let's assume we have a page that allows users to view the shipping status for their orders. Let's also assume that a `ShippingStatusUpdated` event is fired when a shipping status update is processed by the application: - - event(new ShippingStatusUpdated($update)); - -#### The `ShouldBroadcast` Interface - -When a user is viewing one of their orders, we don't want them to have to refresh the page to view status updates. Instead, we want to broadcast the updates to the application as they are created. So, we need to mark the `ShippingStatusUpdated` event with the `ShouldBroadcast` interface. This will instruct Laravel to broadcast the event when it is fired: - - update->order_id); - } - -#### Authorizing Channels - -Remember, users must be authorized to listen on private channels. We may define our channel authorization rules in the `boot` method of the `BroadcastServiceProvider`. In this example, we need to verify that any user attempting to listen on the private `order.1` channel is actually the creator of the order: - - Broadcast::channel('order.*', function ($user, $orderId) { - return $user->id === Order::findOrNew($orderId)->user_id; - }); - -The `channel` method accepts two arguments: the name of the channel and a callback which returns `true` or `false` indicating whether the user is authorized to listen on the channel. - -All authorization callbacks receive the currently authenticated user as their first argument and any additional wildcard parameters as their subsequent arguments. In this example, we are using the `*` character to indicate that the "ID" portion of the channel name is a wildcard. - -#### Listening For Event Broadcasts - -Next, all that remains is to listen for the event in our JavaScript application. We can do this using Laravel Echo. First, we'll use the `private` method to subscribe to the private channel. Then, we may use the `listen` method to listen for the `ShippingStatusUpdated` event. By default, all of the event's public properties will be included on the broadcast event: - - Echo.private('order.' + orderId) - .listen('ShippingStatusUpdated', (e) => { - console.log(e.update); - }); - - -## Defining Broadcast Events - -To inform Laravel that a given event should be broadcast, implement the `Illuminate\Contracts\Broadcasting\ShouldBroadcast` interface on the event class. This interface is already imported into all event classes generated by the framework so you may easily add it to any of your events. - -The `ShouldBroadcast` interface requires you to implement a single method: `broadcastOn`. The `broadcastOn` method should return a channel or array of channels that the event should broadcast on. The channels should be instances of `Channel`, `PrivateChannel`, or `PresenceChannel`. Instances of `Channel` represent public channels that any user my subscribe to, while `PrivateChannels` and `PresenceChannels` represent private channels that require [channel authorization](#authorizing-channels): - - user = $user; - } - - /** - * Get the channels the event should broadcast on. - * - * @return Channel|array - */ - public function broadcastOn() - { - return new PrivateChannel('user.'.$this->user->id); - } - } - -Then, you only need to [fire the event](/docs/{{version}}/events) as you normally would. Once the event has been fired, a [queued job](/docs/{{version}}/queues) will automatically broadcast the event over your specified broadcast driver. - - -### Broadcast Data - -When an event is broadcast, all of its `public` properties are automatically serialized and broadcast as the event's payload, allowing you to access any of its public data from your JavaScript application. So, for example, if your event has a single public `$user` property that contains an Eloquent model, the event's broadcast payload would be: - - { - "user": { - "id": 1, - "name": "Patrick Stewart" - ... - } - } - -However, if you wish to have more fine-grained control over your broadcast payload, you may add a `broadcastWith` method to your event. This method should return the array of data that you wish to broadcast as the event payload: - - /** - * Get the data to broadcast. - * - * @return array - */ - public function broadcastWith() - { - return ['id' => $this->user->id]; - } - - -### Broadcast Queue - -By default, each broadcast event is placed on the default queue for the default queue connection specified in your `queue.php` configuration file. You may customize the queue used by the broadcaster by defining a `broadcastQueue` property on your event class. This property should specify the name of the queue you wish to use when broadcasting: - - /** - * The name of the queue on which to place the event. - * - * @var string - */ - public $broadcastQueue = 'your-queue-name'; - - -## Authorizing Channels - -Private channels require you to authorize that the currently authenticated user can actually listen on the channel. This is accomplished by making an HTTP request to your Laravel application with the channel name and allowing your application to determine if the user can listen on that channel. When using [Laravel Echo](#installing-laravel-echo), the HTTP request to authorize subscriptions to private channels will be made automatically; however, you do need to define the proper routes to respond to these requests. - - -### Defining Authorization Routes - -Thankfully, Laravel makes it easy to define the routes to respond to channel authorization requests. In the `BroadcastServiceProvider` included with your Laravel application, you will see a call to the `Broadcast::routes` method. This method will register the `/broadcasting/auth` route to handle authorization requests: - - Broadcast::routes(); - -The `Broadcast::routes` method will automatically place its routes within the `web` middleware group; however, you may pass an array of route attributes to the method if you would like to customize the assigned attributes: - - Broadcast::routes($attributes); - - -### Defining Authorization Callbacks - -Next, we need to define the logic that will actually perform the channel authorization. Like defining the authorization routes, this is also done in the `boot` method of the `BroadcastServiceProvider`. In this method, you may use the `Broadcast::channel` method to register channel authorization callbacks: - - Broadcast::channel('order.*', function ($user, $orderId) { - return $user->id === Order::findOrNew($orderId)->user_id; - }); - -The `channel` method accepts two arguments: the name of the channel and a callback which returns `true` or `false` indicating whether the user is authorized to listen on the channel. - -All authorization callbacks receive the currently authenticated user as their first argument and any additional wildcard parameters as their subsequent arguments. In this example, we are using the `*` character to indicate that the "ID" portion of the channel name is a wildcard. - - -## Broadcasting Events - -Once you have defined an event and marked it with the `ShouldBroadcast` interface, you only need to fire the event using the `event` function. The event dispatcher will notice that the event is marked with the `ShouldBroadcast` interface and will queue the event for broadcasting: - - event(new ShippingStatusUpdated($update)); - - -### Only To Others - -When building an application that utilizes event broadcasting, you may substitute the `event` function with the `broadcast` function. Like the `event` function, the `broadcast` function dispatches the event to your server-side listeners: - - broadcast(new ShippingStatusUpdated($update)); - -However, the `broadcast` function also exposes the `toOthers` method which allows you to exclude the current user from the broadcast's recipients: - - broadcast(new ShippingStatusUpdated($update))->toOthers(); - -To better understand when you may want to use the `toOthers` method, let's imagine a task list application where a user may create a new task by entering a task name. To create a task, your application might make a request to a `/task` end-point which broadcasts the task's creation and returns a JSON representation of the new task. When your JavaScript application receives the response from the end-point, it might directly insert the new task into its task list like so: - - this.$http.post('/task', task) - .then((response) => { - this.tasks.push(response.data); - }); - -However, remember that we also broadcast the task's creation. If your JavaScript application is listening for this event in order to add tasks to the task list, you will have duplicate tasks in your list: one from the end-point and one from the broadcast. - -You may solve this by using the `toOthers` method to instruct the broadcaster to not broadcast the event to the current user. - -#### Configuration - -When you initialize a Laravel Echo instance, a socket ID is assigned to the connection. If you are using [Vue](https://vuejs.org) and Vue Resource, the socket ID will automatically be attached to every outgoing request as a `X-Socket-ID` header. Then, when you call the `toOthers` method, Laravel will extract the socket ID from the header and instruct the broadcaster to not broadcast to any connections with that socket ID. - -If you are not using Vue and Vue Resource, you will need to manually configure your JavaScript application to send the `X-Socket-ID` header. You may retrieve the socket ID using the `Echo.socketId` method: - - var socketId = Echo.socketId(); - - -## Receiving Broadcasts - - -### Installing Laravel Echo - -Laravel Echo is a JavaScript library that makes it painless to subscribe to channels and listen for events broadcast by Laravel. You may install Echo via the NPM package manager. In this example, we will also install the `pusher-js` package since we will be using the Pusher broadcaster: - - npm install --save laravel-echo pusher-js - -Once Echo is installed, you are ready to create a fresh Echo instance in your application's JavaScript. A great place to do this is at the bottom of the `resources/assets/js/bootstrap.js` file that is included with the Laravel framework: - - import Echo from "laravel-echo" - - window.Echo = new Echo({ - broadcaster: 'pusher', - key: 'your-pusher-key' - }); - - -### Listening For Events - -Once you have installed and instantiated Echo, you are ready to start listening for event broadcasts. First, use the `channel` method to retrieve an instance of a channel, then call the `listen` method to listen for a specified event: - - Echo.channel('orders') - .listen('OrderShipped', (e) => { - console.log(e.order.name); - }); - -If you would like to listen for events on a private channel, use the `private` method instead. You may continue to chain calls to the `listen` method to listen for multiple events on a single channel: - - Echo.private('orders') - .listen(...) - .listen(...) - .listen(...); - - -### Namespaces - -You may have noticed in the examples above that we did not specify the full namespace for the event classes. This is because Echo will automatically assume the events are located in the `App\Events` namespace. However, you may configure the root namespace when you instantiate Echo by passing a `namespace` configuration option: - - window.Echo = new Echo({ - broadcaster: 'pusher', - key: 'your-pusher-key', - namespace: 'App.Other.Namespace' - }); - -Alternatively, you may prefix event classes with a `.` when subscribing to them using Echo. This will allow you to always specify the fully-qualified class name: - - Echo.channel('orders') - .listen('.Namespace.Event.Class', (e) => { - // - }); - - -## Presence Channels - -Presence channels build on the security of private channels while exposing the additional feature of awareness of who is subscribed to the channel. This makes it easy to build powerful, collaborative application features such as notifying users when another user is viewing the same page. - - -### Authorizing Presence Channels - -All presence channels are also private channels; therefore, users must be [authorized to access them](#authorizing-channels). However, when defining authorization callbacks for presence channels, you will not return `true` if the user is authorized to join the channel. Instead, you should return an array of data about the user. - -The data returned by the authorization callback will be made available to the presence channel event listeners in your JavaScript application. If the user is not authorized to join the presence channel, you should return `false` or `null`: - - Broadcast::channel('chat.*', function ($user, $roomId) { - if ($user->canJoinRoom($roomId)) { - return ['id' => $user->id, 'name' => $user->name]; - } - }); - - -### Joining Presence Channels - -To join a presence channel, you may use Echo's `join` method. The `join` method will return a `PresenceChannel` implementation which, along with exposing the `listen` method, allows you to subscribe to the `here`, `joining`, and `leaving` events. - - Echo.join('chat.' + roomId) - .here((users) => { - // - }) - .joining((user) => { - console.log(user.name); - }) - .leaving((user) => { - console.log(user.name); - }); - -The `here` callback will be executed immediately once the channel is joined successfully, and will receive an array containing the user information for all of the other users currently subscribed to the channel. The `joining` method will be executed when a new user joins a channel, while the `leaving` method will be executed when a user leaves the channel. - - -### Broadcasting To Presence Channels - -Presence channels may receive events just like public or private channels. Using the example of a chatroom, we may want to broadcast `NewMessage` events to the room's presence channel. To do so, we'll return an instance of `PresenceChannel` from the event's `broadcastOn` method: - - /** - * Get the channels the event should broadcast on. - * - * @return Channel|array - */ - public function broadcastOn() - { - return new PresenceChannel('room.'.$this->message->room_id); - } - -Like public or private events, presence channel events may be broadcast using the `broadcast` function. As with other events, you may use the `toOthers` method to exclude the current user from receiving the broadcast: - - broadcast(new NewMessage($message)); - - broadcast(new NewMessage($message))->toOthers(); - -You may listen for the join event via Echo's `listen` method: - - Echo.join('chat.' + roomId) - .here(...) - .joining(...) - .leaving(...) - .listen('NewMessage', (e) => { - // - }); - - -## Notifications - -By pairing event broadcasting with [notifications](/docs/{{version}}/notifications), your JavaScript application may receive new notifications as they occur without needing to refresh the page. First, be sure to read over the documentation on using [the broadcast notification channel](/docs/{{version}}/notifications#broadcast-notifications). - -Once you have configured a notification to use the broadcast channel, you may listen for the broadcast events using Echo's `notification` method. Remember, the channel name should match the class name of the entity receiving the notifications: - - Echo.private('App.User.' + userId) - .notification((notification) => { - console.log(notification.type); - }); - -In this example, all notifications sent to `App\User` instances via the `broadcast` channel would be received by the callback. A channel authorization callback for the `App.User.*` channel is included in the default `BroadcastServiceProvider` that ships with the Laravel framework. diff --git a/cache.md b/cache.md index d3039f0..9b14019 100644 --- a/cache.md +++ b/cache.md @@ -1,335 +1,142 @@ # Cache -- [Configuration](#configuration) - - [Driver Prerequisites](#driver-prerequisites) -- [Cache Usage](#cache-usage) - - [Obtaining A Cache Instance](#obtaining-a-cache-instance) - - [Retrieving Items From The Cache](#retrieving-items-from-the-cache) - - [Storing Items In The Cache](#storing-items-in-the-cache) - - [Removing Items From The Cache](#removing-items-from-the-cache) -- [Cache Tags](#cache-tags) - - [Storing Tagged Cache Items](#storing-tagged-cache-items) - - [Accessing Tagged Cache Items](#accessing-tagged-cache-items) - - [Removing Tagged Cache Items](#removing-tagged-cache-items) -- [Adding Custom Cache Drivers](#adding-custom-cache-drivers) - - [Writing The Driver](#writing-the-driver) - - [Registering The Driver](#registering-the-driver) -- [Events](#events) +- [ပြင်ဆင်ခြင်း](#configuration) +- [Cache အသုံးပြုသည့်ပုံစံ](#cache-usage) +- [တန်ဖိုး ထပ်တိုးခြင်း နှင့် လျော့ချခြင်း](#increments-and-decrements) +- [Cache များအား အုပ်စုဖွဲ့ခြင်း](#cache-tags) +- [Database Cache](#database-cache) -## Configuration +## ပြင်ဆင်ခြင်း -Laravel provides an expressive, unified API for various caching backends. The cache configuration is located at `config/cache.php`. In this file you may specify which cache driver you would like used by default throughout your application. Laravel supports popular caching backends like [Memcached](http://memcached.org) and [Redis](http://redis.io) out of the box. +Caching ပြုလုပ်နည်းပုံစံမျိုးစုံတွက် Laravel မှ API ထုတ်ပေးပြီးသားဖြစ်ပါတယ်။ Cache configuration အတွက် `app/config/cache.php` ဖိုင်ထဲမှာသွားပြင်ရမှာပါ။ Application တစ်ခုလုံးအတွက်အသုံးပြုမဲ့ cache driver ကို အဲ့ဒီဖိုင်ထဲမှာ သတ်မှတ်ပေးရမှာပါ။ [Memcached](http://memcached.org) နှင့် [Redis](http://redis.io) ကဲ့သိုသော လူသုံးများပြီး popular ဖြစ်တဲ့ caching methods တွေကို laravel မှာ အထောက်အပံ့ပေးထားပါတယ်။ -The cache configuration file also contains various other options, which are documented within the file, so make sure to read over these options. By default, Laravel is configured to use the `file` cache driver, which stores the serialized, cached objects in the filesystem. For larger applications, it is recommended that you use a more robust driver such as Memcached or Redis. You may even configure multiple cache configurations for the same driver. - - -### Driver Prerequisites - -#### Database - -When using the `database` cache driver, you will need to setup a table to contain the cache items. You'll find an example `Schema` declaration for the table below: - - Schema::create('cache', function($table) { - $table->string('key')->unique(); - $table->text('value'); - $table->integer('expiration'); - }); - -> {tip} You may also use the `php artisan cache:table` Artisan command to generate a migration with the proper schema. - -#### Memcached - -Using the Memcached driver requires the [Memcached PECL package](http://pecl.php.net/package/memcached) to be installed. You may list all of your Memcached servers in the `config/cache.php` configuration file: - - 'memcached' => [ - [ - 'host' => '127.0.0.1', - 'port' => 11211, - 'weight' => 100 - ], - ], - -You may also set the `host` option to a UNIX socket path. If you do this, the `port` option should be set to `0`: - - 'memcached' => [ - [ - 'host' => '/var/run/memcached/memcached.sock', - 'port' => 0, - 'weight' => 100 - ], - ], - -#### Redis - -Before using a Redis cache with Laravel, you will need to install the `predis/predis` package (~1.0) via Composer. - -For more information on configuring Redis, consult its [Laravel documentation page](/docs/{{version}}/redis#configuration). +အဲ့ဒီ cache configuration ဖိုင်ထဲမှာ ကျန်တဲ့ options တွေလဲ အများကြီးရှိပါသေးတယ်။ အဲ့ဒီအတွက်လဲ ဖိုင်ထဲမှာ တစ်ခါတည်း လမ်းညွှန်ချက်ရေးပေးထားပြီးသားပါ။ အကယ်၍ အဲ့ဒီ options တွေကိုအသုံးပြုမယ်ဆိုရင်တော့ option နဲ့ပတ်သက်တဲ့လမ်းညွှန်ချက်ကို သေသေချာချာဖတ်ပြီးမှ အသုံးပြုဖို့လိုအပ်ပါတယ်။ ပုံမှန်အတိုင်းဆိုရင်တော့ laravel ဟာ `file` cache driver အတွက် ပြင်ဆင်ပေးထားပါတယ်။ အဲ့ဒီ cache ဖိုင် objects တွေကို နံပါတ်စဉ်အတိုင်း filesystem ထဲမှာသွားသိမ်းထားပါတယ်။ Application အကြီးတွေအတွက်ဆိုရင်တော့ Memcached သို့မဟုတ် APC (Alternative PHP Cache) ကဲ့သို့သော in-memory cache တွေကိုအသုံးပြုသင့်ပါတယ်။ -## Cache Usage - - -### Obtaining A Cache Instance - -The `Illuminate\Contracts\Cache\Factory` and `Illuminate\Contracts\Cache\Repository` [contracts](/docs/{{version}}/contracts) provide access to Laravel's cache services. The `Factory` contract provides access to all cache drivers defined for your application. The `Repository` contract is typically an implementation of the default cache driver for your application as specified by your `cache` configuration file. +## Cache အသုံးပြုသည့်ပုံစံ -However, you may also use the `Cache` facade, which is what we will use throughout this documentation. The `Cache` facade provides convenient, terse access to the underlying implementations of the Laravel cache contracts: +#### အချက်အလက်ကို Cache ထဲတွင်သိမ်းဆည်းခြင်း - addMinutes(10); - class UserController extends Controller - { - /** - * Show a list of all users of the application. - * - * @return Response - */ - public function index() - { - $value = Cache::get('key'); + Cache::put('key', 'value', $expiresAt); - // - } - } +#### အချက်အလက်သည် Cache ထဲတွင် ရှိမနေလျှင် ထပ်ထည့်ခြင်း -#### Accessing Multiple Cache Stores + Cache::add('key', 'value', $minutes); -Using the `Cache` facade, you may access various cache stores via the `store` method. The key passed to the `store` method should correspond to one of the stores listed in the `stores` configuration array in your `cache` configuration file: +အကယ်၍ အချက်အလက်ဟာ cache ထဲမှာ **ရှိနေလျှင်** `add` method ဟာ `true` return ပြန်မှာဖြစ်ပြီး၊ အဲ့လိုမဟုတ်ရင်တော့ `false` return ပြန်မှာဖြစ်ပါတယ်။ - $value = Cache::store('file')->get('foo'); +#### Cache ရှိမရှိ စစ်ဆေးခြင်း - Cache::store('redis')->put('bar', 'baz', 10); + if (Cache::has('key')) + { + // + } - -### Retrieving Items From The Cache +#### Cache ထဲမှ အချက်အလက်ကို ရယူခြင်း -The `get` method on the `Cache` facade is used to retrieve items from the cache. If the item does not exist in the cache, `null` will be returned. If you wish, you may pass a second argument to the `get` method specifying the default value you wish to be returned if the item doesn't exist: + $value = Cache::get('key'); - $value = Cache::get('key'); +#### အချက်အလက်ရယူခြင်း (သို့မဟုတ်) Default Value တစ်ခု return ပြန်ခြင်း - $value = Cache::get('key', 'default'); + $value = Cache::get('key', 'default'); + $value = Cache::get('key', function() { return 'default'; }); -You may even pass a `Closure` as the default value. The result of the `Closure` will be returned if the specified item does not exist in the cache. Passing a Closure allows you to defer the retrieval of default values from a database or other external service: +#### အချက်အလက်ကို Cache ထဲသို့ အကန့်မသတ်မရှိသိမ်းဆည်းခြင်း - $value = Cache::get('key', function() { - return DB::table(...)->get(); - }); + Cache::forever('key', 'value'); -#### Checking For Item Existence +တစ်ခါတစ်ရံမှာ cache ထဲက အချက်အလက်ကိုလဲ ယူချင်တယ်၊ အကယ်၍ အဲ့ဒီအချက်အလက်ရှိမနေဘူးဆိုရင်လည်း cache ထဲကို default value တစ်ခု ထည့်ထားခဲ့ချင်တဲ့ အခြေအနေတွေရှိလာနိုင်ပါတယ်။ အဲ့ဒီလို အခြေအနေမျိုးအတွက် `Cache::remember` method ကိုအသုံးပြုနိုင်ပါတယ်။ -The `has` method may be used to determine if an item exists in the cache: + $value = Cache::remember('users', $minutes, function() + { + return DB::table('users')->get(); + }); - if (Cache::has('key')) { - // - } +`remember` နဲ့ `forever` method နှစ်ခုလုံးကို ပေါင်းစပ်ပြီး အသုံးပြုနိုင်ပါသေးတယ်။ -#### Incrementing / Decrementing Values + $value = Cache::rememberForever('users', function() + { + return DB::table('users')->get(); + }); -The `increment` and `decrement` methods may be used to adjust the value of integer items in the cache. Both of these methods accept an optional second argument indicating the amount by which to increment or decrement the item's value: +Cache ထဲမှာသိမ်းဆည်းလိုက်တဲ့ အချက်အလက်တွေဟာ နံပါတ်စဉ်အလိုက်သိမ်းဆည်းတာဖြစ်တဲ့အတွက် သင့်အနေနဲ့ ဘယ်လို အချက်အလက်အမျိုးအစားကိုမဆို လွတ်လပ်စွာ သိမ်းဆည်းနိုင်ကြောင်း သတိပြုပါလေ။ - Cache::increment('key'); - Cache::increment('key', $amount); - Cache::decrement('key'); - Cache::decrement('key', $amount); +#### Cache ထဲရှိ အချက်အလက်ကို ဆွဲထုတ်ခြင်း -#### Retrieve & Store +Cache ထဲမှ အချက်အလက်ကို ရယူအသုံးပြုပြီးတာနဲ့ ဖျက်ပြစ်လိုက်ချင်တယ်ဆိုရင်တော့၊ `pull` method ကိုအသုံးပြုနိုင်ပါတယ်။ -Sometimes you may wish to retrieve an item from the cache, but also store a default value if the requested item doesn't exist. For example, you may wish to retrieve all users from the cache or, if they don't exist, retrieve them from the database and add them to the cache. You may do this using the `Cache::remember` method: + $value = Cache::pull('key'); - $value = Cache::remember('users', $minutes, function() { - return DB::table('users')->get(); - }); +#### Cache ထဲမှ အချက်အလက်ကို ပယ်ဖျက်ခြင်း -If the item does not exist in the cache, the `Closure` passed to the `remember` method will be executed and its result will be placed in the cache. + Cache::forget('key'); -#### Retrieve & Delete + +## တန်ဖိုး ထပ်တိုးခြင်း နှင့် လျော့ချခြင်း -If you need to retrieve an item from the cache and then delete the item, you may use the `pull` method. Like the `get` method, `null` will be returned if the item does not exist in the cache: +`file` နဲ့ `database` driver မှလွဲ၍ ကျန်တဲ့ cache drivers တွေအားလုံးကို `increment` နဲ့ `decrement`လုပ်ဆောင်ချက်တွေအတွက် အထောက်အပံ့ပေးထားပါတယ်။ - $value = Cache::pull('key'); +#### အချက်အလက်တန်ဖိုး ထပ်တိုးခြင်း - -### Storing Items In The Cache + Cache::increment('key'); -You may use the `put` method on the `Cache` facade to store items in the cache. When you place an item in the cache, you need to specify the number of minutes for which the value should be cached: + Cache::increment('key', $amount); - Cache::put('key', 'value', $minutes); +#### အချက်အလက်တန်ဖိုးလျော့ချခြင်း -Instead of passing the number of minutes as an integer, you may also pass a `DateTime` instance representing the expiration time of the cached item: + Cache::decrement('key'); - $expiresAt = Carbon::now()->addMinutes(10); + Cache::decrement('key', $amount); - Cache::put('key', 'value', $expiresAt); - -#### Store If Not Present - -The `add` method will only add the item to the cache if it does not already exist in the cache store. The method will return `true` if the item is actually added to the cache. Otherwise, the method will return `false`: - - Cache::add('key', 'value', $minutes); - -#### Storing Items Forever - -The `forever` method may be used to store an item in the cache permanently. Since these items will not expire, they must be manually removed from the cache using the `forget` method: - - Cache::forever('key', 'value'); - -> {tip} If you are using the Memcached driver, items that are stored "forever" may be removed when the cache reaches its size limit. - - -### Removing Items From The Cache - -You may remove items from the cache using the `forget` method: - - Cache::forget('key'); + +## Cache များအား အုပ်စုဖွဲ့ခြင်း -You may clear the entire cache using the `flush` method: +> **သတိပြုရန်:** `file` သို့မဟုတ် `database` cache driver သုံးထားရင်တော့ Cache tags ကို အထောက်အပံ့ပေးမှာမဟုတ်ပါဘူး။ ၎င်းအပြင် cache ကို tags တွေနဲ့တွဲသုံးမယ်ဆိုရင် အဲ့ဒီ cache ကို အမြဲတမ်းသိမ်းဆည်းထားမှာဖြစ်တဲ့အတွက် `memcached` ကဲသို့သော driver ကိုအသုံးပြုမှသာ permormance အတွက်ပိုပြီးအဆင်ပြေစေမှာပါ။ အဲ့ဒီတော့မှ အသုံးမလိုတော့တဲ့ အချက်အလက်တွေကို အလိုအလျှောက် ပယ်ဖျက်ပေးမှာဖြစ်ပါတယ်။ - Cache::flush(); +#### Cache များအား အုပ်စုဖွဲ့ခြင်း -> {note} Flushing the cache does not respect the cache prefix and will remove all entries from the cache. Consider this carefully when clearing a cache which is shared by other applications. +Cache ထဲမှာရှိတဲ့ ဆက်စပ်နေတဲ့ အချက်အလက်တွေကို အတူတကွအုပ်စုဖွဲ့ပေးခြင်းကို cache tags ကပြုလုပ်ပေးနိုင်ပါတယ်။ ပြီးရင်တော့ ပေးထားခဲ့တဲနာမည်အတိုင်းပြန်ပြီး လွယ်လွယ်ကူကူပဲ ပြန်လည်ပယ်ဖျက်နိုင်ပါတယ်။ Cache တွေကို တစ်ခုတစည်းထဲ အုပ်စုဖွဲ့ထားဖို့အတွက် `tags` method ကိုအသုံးပြုရပါမယ်။ - -## Cache Tags +Cache တွေကို တွဲစပ်ဖို့အတွက် `tags` method ထဲသို့ အမည်များကို `,` ခံ၍သော်လည်းကောင်း၊ array အနေနှင့် passing ပေး၍သော်လည်းကောင်း သိမ်းဆည်းနိုင်ပါတယ်။ -> {note} Cache tags are not supported when using the `file` or `database` cache drivers. Furthermore, when using multiple tags with caches that are stored "forever", performance will be best with a driver such as `memcached`, which automatically purges stale records. + Cache::tags('people', 'authors')->put('John', $john, $minutes); - -### Storing Tagged Cache Items + Cache::tags(array('people', 'artists'))->put('Anne', $anne, $minutes); -Cache tags allow you to tag related items in the cache and then flush all cached values that have been assigned a given tag. You may access a tagged cache by passing in an ordered array of tag names. For example, let's access a tagged cache and `put` value in the cache: +Cache တွေကိုတစ်ခုတစည်းထဲ အုပ်စုဖွဲ့ထားဖို့အတွက် နှစ်သက်ရာ caching method ကိုအသုံးပြုနိုင်ပါတယ်။ `remember`, `forever` နှင့် `rememberForever` စတာတွေအပါအဝင်ပေါ့။ `increment` နဲ့ `decrement` method တွေကိုတော့ အသုံးပြုလို့ရမှာမဟုတ်ပါဘူး။ - Cache::tags(['people', 'artists'])->put('John', $john, $minutes); +#### အုပ်စုဖွဲ့ထားသော Cache ထဲမှ အချက်အလက်ကို ရယူခြင်း - Cache::tags(['people', 'authors'])->put('Anne', $anne, $minutes); +အုပ်စုဖွဲ့ထားသော cache ထဲမှ အချက်အလက်ကို ပြန်လည်ရယူဖို့အတွက် အုပ်စုဖွဲ့ခြင်းပြုလုပ်စဉ်က ပေးထားခဲ့သော အမည်များအတိုင်းအစဉ်လိုက်ပြန်လည် passing ပေးပြီး ရယူနိုင်ပါတယ်။ - -### Accessing Tagged Cache Items + $anne = Cache::tags('people', 'artists')->get('Anne'); -To retrieve a tagged cache item, pass the same ordered list of tags to the `tags` method and then call the `get` method with the key you wish to retrieve: + $john = Cache::tags(array('people', 'authors'))->get('John'); - $john = Cache::tags(['people', 'artists'])->get('John'); +ပြန်လည်ပယ်ဖျက်ချင်တယ်ဆိုလျင်လဲ အုပ်စုဖွဲ့ခြင်းပြုလုပ်စဉ်ကပေးထားခဲ့သော နာမည်တစ်ခု သို့မဟုတ် တစ်ခုထက်ပိုသော အမည်များကို အသုံးပြုပြီးပယ်ဖျက်နိုင်ပါတယ်။ အောက်မှာပေးထားတဲ့ ဥပမာကို ကြည့်မယ်ဆိုရင် `people` အုပ်စုကော `author` အုပ်စုကိုကော ပယ်ဖျက်လိုက်တာဖြစ်ပါတယ်။ အဲ့ဒီအတွက် အဲ့ဒီအုပ်စုနှစ်ခုထဲမှာပါတဲ့ "Anne" နဲ့ "John" ကို cache ထဲကနေ ဖျက်သွားမှာဖြစ်ပါတယ်။ - $anne = Cache::tags(['people', 'authors'])->get('Anne'); + Cache::tags('people', 'authors')->flush(); - -### Removing Tagged Cache Items +အောက်မှာပြထားတဲ့ ဥပမာအရဆိုရင် `authors` အုပ်စုကိုပဲပယ်ဖျက်လိုက်တာဖြစ်ပါတယ်။ အဲ့ဒါကြောင့် `authors` အုပ်စုထဲမှာပါတဲ့ "John" ကိုပဲဖျက်သွားမှာဖြစ်ပြီး "Anne" ကိုဖျက်သွားမှာမဟုတ်ပါဘူး။ အပေါ်ကဥပမာနဲ့ အောက်က ဥပမာကို ယှဉ်ကြည့်ပါ။ -You may flush all items that are assigned a tag or list of tags. For example, this statement would remove all caches tagged with either `people`, `authors`, or both. So, both `Anne` and `John` would be removed from the cache: - - Cache::tags(['people', 'authors'])->flush(); + Cache::tags('authors')->flush(); -In contrast, this statement would remove only caches tagged with `authors`, so `Anne` would be removed, but not `John`: + +## Database Cache - Cache::tags('authors')->flush(); +`database` cache driver ကိုအသုံးပြုမယ်ဆိုရင်တော့ cache အချက်အလက်တွေကိုသိမ်းဆည်းဖို့အတွက် table တစ်ခုပြုလုပ်ပေးဖို့ လိုပါတယ်။ အောက်မှာ `Schema` နဲ့ cache table ပြုလုပ်ထားပုံကို ဥပမာအနေနဲ့ပြပေးထားပါတယ်။ - -## Adding Custom Cache Drivers - - -### Writing The Driver - -To create our custom cache driver, we first need to implement the `Illuminate\Contracts\Cache\Store` [contract](/docs/{{version}}/contracts) contract. So, a MongoDB cache implementation would look something like this: - - {tip} If you're wondering where to put your custom cache driver code, you could create an `Extensions` namespace within your `app` directory. However, keep in mind that Laravel does not have a rigid application structure and you are free to organize your application according to your preferences. - - -### Registering The Driver - -To register the custom cache driver with Laravel, we will use the `extend` method on the `Cache` facade. The call to `Cache::extend` could be done in the `boot` method of the default `App\Providers\AppServiceProvider` that ships with fresh Laravel applications, or you may create your own service provider to house the extension - just don't forget to register the provider in the `config/app.php` provider array: - - -## Events - -To execute code on every cache operation, you may listen for the [events](/docs/{{version}}/events) fired by the cache. Typically, you should place these event listeners within your `EventServiceProvider`: - - /** - * The event listener mappings for the application. - * - * @var array - */ - protected $listen = [ - 'Illuminate\Cache\Events\CacheHit' => [ - 'App\Listeners\LogCacheHit', - ], - - 'Illuminate\Cache\Events\CacheMissed' => [ - 'App\Listeners\LogCacheMissed', - ], - - 'Illuminate\Cache\Events\KeyForgotten' => [ - 'App\Listeners\LogKeyForgotten', - ], - - 'Illuminate\Cache\Events\KeyWritten' => [ - 'App\Listeners\LogKeyWritten', - ], - ]; + Schema::create('cache', function($table) + { + $table->string('key')->unique(); + $table->text('value'); + $table->integer('expiration'); + }); \ No newline at end of file diff --git a/collections.md b/collections.md deleted file mode 100644 index 808aa49..0000000 --- a/collections.md +++ /dev/null @@ -1,1367 +0,0 @@ -# Collections - -- [Introduction](#introduction) - - [Creating Collections](#creating-collections) -- [Available Methods](#available-methods) - - -## Introduction - -The `Illuminate\Support\Collection` class provides a fluent, convenient wrapper for working with arrays of data. For example, check out the following code. We'll use the `collect` helper to create a new collection instance from the array, run the `strtoupper` function on each element, and then remove all empty elements: - - $collection = collect(['taylor', 'abigail', null])->map(function ($name) { - return strtoupper($name); - }) - ->reject(function ($name) { - return empty($name); - }); - - -As you can see, the `Collection` class allows you to chain its methods to perform fluent mapping and reducing of the underlying array. In general, collections are immutable, meaning every `Collection` method returns an entirely new `Collection` instance. - - -### Creating Collections - -As mentioned above, the `collect` helper returns a new `Illuminate\Support\Collection` instance for the given array. So, creating a collection is as simple as: - - $collection = collect([1, 2, 3]); - -> {tip} The results of [Eloquent](/docs/{{version}}/eloquent) queries are always returned as `Collection` instances. - - -## Available Methods - -For the remainder of this documentation, we'll discuss each method available on the `Collection` class. Remember, all of these methods may be chained to fluently manipulating the underlying array. Furthermore, almost every method returns a new `Collection` instance, allowing you to preserve the original copy of the collection when necessary: - - - -
    - -[all](#method-all) -[avg](#method-avg) -[chunk](#method-chunk) -[collapse](#method-collapse) -[combine](#method-combine) -[contains](#method-contains) -[count](#method-count) -[diff](#method-diff) -[diffKeys](#method-diffkeys) -[each](#method-each) -[every](#method-every) -[except](#method-except) -[filter](#method-filter) -[first](#method-first) -[flatMap](#method-flatmap) -[flatten](#method-flatten) -[flip](#method-flip) -[forget](#method-forget) -[forPage](#method-forpage) -[get](#method-get) -[groupBy](#method-groupby) -[has](#method-has) -[implode](#method-implode) -[intersect](#method-intersect) -[isEmpty](#method-isempty) -[keyBy](#method-keyby) -[keys](#method-keys) -[last](#method-last) -[map](#method-map) -[max](#method-max) -[merge](#method-merge) -[min](#method-min) -[only](#method-only) -[pluck](#method-pluck) -[pop](#method-pop) -[prepend](#method-prepend) -[pull](#method-pull) -[push](#method-push) -[put](#method-put) -[random](#method-random) -[reduce](#method-reduce) -[reject](#method-reject) -[reverse](#method-reverse) -[search](#method-search) -[shift](#method-shift) -[shuffle](#method-shuffle) -[slice](#method-slice) -[sort](#method-sort) -[sortBy](#method-sortby) -[sortByDesc](#method-sortbydesc) -[splice](#method-splice) -[sum](#method-sum) -[take](#method-take) -[toArray](#method-toarray) -[toJson](#method-tojson) -[transform](#method-transform) -[union](#method-union) -[unique](#method-unique) -[values](#method-values) -[where](#method-where) -[whereStrict](#method-wherestrict) -[whereIn](#method-wherein) -[whereInLoose](#method-whereinloose) -[zip](#method-zip) - -
    - - -## Method Listing - - - - -#### `all()` {#collection-method .first-collection-method} - -The `all` method returns the underlying array represented by the collection: - - collect([1, 2, 3])->all(); - - // [1, 2, 3] - - -#### `avg()` {#collection-method} - -The `avg` method returns the average of all items in the collection: - - collect([1, 2, 3, 4, 5])->avg(); - - // 3 - -If the collection contains nested arrays or objects, you should pass a key to use for determining which values to calculate the average: - - $collection = collect([ - ['name' => 'JavaScript: The Good Parts', 'pages' => 176], - ['name' => 'JavaScript: The Definitive Guide', 'pages' => 1096], - ]); - - $collection->avg('pages'); - - // 636 - - -#### `chunk()` {#collection-method} - -The `chunk` method breaks the collection into multiple, smaller collections of a given size: - - $collection = collect([1, 2, 3, 4, 5, 6, 7]); - - $chunks = $collection->chunk(4); - - $chunks->toArray(); - - // [[1, 2, 3, 4], [5, 6, 7]] - -This method is especially useful in [views](/docs/{{version}}/views) when working with a grid system such as [Bootstrap](http://getbootstrap.com/css/#grid). Imagine you have a collection of [Eloquent](/docs/{{version}}/eloquent) models you want to display in a grid: - - @foreach ($products->chunk(3) as $chunk) -
    - @foreach ($chunk as $product) -
    {{ $product->name }}
    - @endforeach -
    - @endforeach - - -#### `collapse()` {#collection-method} - -The `collapse` method collapses a collection of arrays into a single, flat collection: - - $collection = collect([[1, 2, 3], [4, 5, 6], [7, 8, 9]]); - - $collapsed = $collection->collapse(); - - $collapsed->all(); - - // [1, 2, 3, 4, 5, 6, 7, 8, 9] - - -#### `combine()` {#collection-method} - -The `combine` method combines the keys of the collection with the values of another array or collection: - - $collection = collect(['name', 'age']); - - $combined = $collection->combine(['George', 29]); - - $combined->all(); - - // ['name' => 'George', 'age' => 29] - - -#### `contains()` {#collection-method} - -The `contains` method determines whether the collection contains a given item: - - $collection = collect(['name' => 'Desk', 'price' => 100]); - - $collection->contains('Desk'); - - // true - - $collection->contains('New York'); - - // false - -You may also pass a key / value pair to the `contains` method, which will determine if the given pair exists in the collection: - - $collection = collect([ - ['product' => 'Desk', 'price' => 200], - ['product' => 'Chair', 'price' => 100], - ]); - - $collection->contains('product', 'Bookcase'); - - // false - -Finally, you may also pass a callback to the `contains` method to perform your own truth test: - - $collection = collect([1, 2, 3, 4, 5]); - - $collection->contains(function ($value, $key) { - return $value > 5; - }); - - // false - - -#### `count()` {#collection-method} - -The `count` method returns the total number of items in the collection: - - $collection = collect([1, 2, 3, 4]); - - $collection->count(); - - // 4 - - -#### `diff()` {#collection-method} - -The `diff` method compares the collection against another collection or a plain PHP `array` based on its values. This method will return the values in the original collection that are not present in the given collection: - - $collection = collect([1, 2, 3, 4, 5]); - - $diff = $collection->diff([2, 4, 6, 8]); - - $diff->all(); - - // [1, 3, 5] - - -#### `diffKeys()` {#collection-method} - -The `diffKeys` method compares the collection against another collection or a plain PHP `array` based on its keys. This method will return the key / value pairs in the original collection that are not present in the given collection: - - $collection = collect([ - 'one' => 10, - 'two' => 20, - 'three' => 30, - 'four' => 40, - 'five' => 50, - ]); - - $diff = $collection->diffKeys([ - 'two' => 2, - 'four' => 4, - 'six' => 6, - 'eight' => 8, - ]); - - $diff->all(); - - // ['one' => 10, 'three' => 30, 'five' => 50] - - -#### `each()` {#collection-method} - -The `each` method iterates over the items in the collection and passes each item to a callback: - - $collection = $collection->each(function ($item, $key) { - // - }); - -If you would like to stop iterating through the items, you may return `false` from your callback: - - $collection = $collection->each(function ($item, $key) { - if (/* some condition */) { - return false; - } - }); - - -#### `every()` {#collection-method} - -The `every` method creates a new collection consisting of every n-th element: - - $collection = collect(['a', 'b', 'c', 'd', 'e', 'f']); - - $collection->every(4); - - // ['a', 'e'] - -You may optionally pass an offset as the second argument: - - $collection->every(4, 1); - - // ['b', 'f'] - - -#### `except()` {#collection-method} - -The `except` method returns all items in the collection except for those with the specified keys: - - $collection = collect(['product_id' => 1, 'price' => 100, 'discount' => false]); - - $filtered = $collection->except(['price', 'discount']); - - $filtered->all(); - - // ['product_id' => 1] - -For the inverse of `except`, see the [only](#method-only) method. - - -#### `filter()` {#collection-method} - -The `filter` method filters the collection using the given callback, keeping only those items that pass a given truth test: - - $collection = collect([1, 2, 3, 4]); - - $filtered = $collection->filter(function ($value, $key) { - return $value > 2; - }); - - $filtered->all(); - - // [3, 4] - -For the inverse of `filter`, see the [reject](#method-reject) method. - - -#### `first()` {#collection-method} - -The `first` method returns the first element in the collection that passes a given truth test: - - collect([1, 2, 3, 4])->first(function ($value, $key) { - return $value > 2; - }); - - // 3 - -You may also call the `first` method with no arguments to get the first element in the collection. If the collection is empty, `null` is returned: - - collect([1, 2, 3, 4])->first(); - - // 1 - - -#### `flatMap()` {#collection-method} - -The `flatMap` method iterates through the collection and passes each value to the given callback. The callback is free to modify the item and return it, thus forming a new collection of modified items. Then, the array is flattened by a level: - - $collection = collect([ - ['name' => 'Sally'], - ['school' => 'Arkansas'], - ['age' => 28] - ]); - - $flattened = $collection->flatMap(function ($values) { - return array_map('strtoupper', $values); - }); - - $flattened->all(); - - // ['name' => 'SALLY', 'school' => 'ARKANSAS', 'age' => '28']; - - -#### `flatten()` {#collection-method} - -The `flatten` method flattens a multi-dimensional collection into a single dimension: - - $collection = collect(['name' => 'taylor', 'languages' => ['php', 'javascript']]); - - $flattened = $collection->flatten(); - - $flattened->all(); - - // ['taylor', 'php', 'javascript']; - -You may optionally pass the function a "depth" argument: - - $collection = collect([ - 'Apple' => [ - ['name' => 'iPhone 6S', 'brand' => 'Apple'], - ], - 'Samsung' => [ - ['name' => 'Galaxy S7', 'brand' => 'Samsung'] - ], - ]); - - $products = $collection->flatten(1); - - $products->values()->all(); - - /* - [ - ['name' => 'iPhone 6S', 'brand' => 'Apple'], - ['name' => 'Galaxy S7', 'brand' => 'Samsung'], - ] - */ - -In this example, calling `flatten` without providing the depth would have also flattened the nested arrays, resulting in `['iPhone 6S', 'Apple', 'Galaxy S7', 'Samsung']`. Providing a depth allows you to restrict the levels of nested arrays that will be flattened. - - -#### `flip()` {#collection-method} - -The `flip` method swaps the collection's keys with their corresponding values: - - $collection = collect(['name' => 'taylor', 'framework' => 'laravel']); - - $flipped = $collection->flip(); - - $flipped->all(); - - // ['taylor' => 'name', 'laravel' => 'framework'] - - -#### `forget()` {#collection-method} - -The `forget` method removes an item from the collection by its key: - - $collection = collect(['name' => 'taylor', 'framework' => 'laravel']); - - $collection->forget('name'); - - $collection->all(); - - // ['framework' => 'laravel'] - -> {note} Unlike most other collection methods, `forget` does not return a new modified collection; it modifies the collection it is called on. - - -#### `forPage()` {#collection-method} - -The `forPage` method returns a new collection containing the items that would be present on a given page number. The method accepts the page number as its first argument and the number of items to show per page as its second argument: - - $collection = collect([1, 2, 3, 4, 5, 6, 7, 8, 9]); - - $chunk = $collection->forPage(2, 3); - - $chunk->all(); - - // [4, 5, 6] - - -#### `get()` {#collection-method} - -The `get` method returns the item at a given key. If the key does not exist, `null` is returned: - - $collection = collect(['name' => 'taylor', 'framework' => 'laravel']); - - $value = $collection->get('name'); - - // taylor - -You may optionally pass a default value as the second argument: - - $collection = collect(['name' => 'taylor', 'framework' => 'laravel']); - - $value = $collection->get('foo', 'default-value'); - - // default-value - -You may even pass a callback as the default value. The result of the callback will be returned if the specified key does not exist: - - $collection->get('email', function () { - return 'default-value'; - }); - - // default-value - - -#### `groupBy()` {#collection-method} - -The `groupBy` method groups the collection's items by a given key: - - $collection = collect([ - ['account_id' => 'account-x10', 'product' => 'Chair'], - ['account_id' => 'account-x10', 'product' => 'Bookcase'], - ['account_id' => 'account-x11', 'product' => 'Desk'], - ]); - - $grouped = $collection->groupBy('account_id'); - - $grouped->toArray(); - - /* - [ - 'account-x10' => [ - ['account_id' => 'account-x10', 'product' => 'Chair'], - ['account_id' => 'account-x10', 'product' => 'Bookcase'], - ], - 'account-x11' => [ - ['account_id' => 'account-x11', 'product' => 'Desk'], - ], - ] - */ - -In addition to passing a string `key`, you may also pass a callback. The callback should return the value you wish to key the group by: - - $grouped = $collection->groupBy(function ($item, $key) { - return substr($item['account_id'], -3); - }); - - $grouped->toArray(); - - /* - [ - 'x10' => [ - ['account_id' => 'account-x10', 'product' => 'Chair'], - ['account_id' => 'account-x10', 'product' => 'Bookcase'], - ], - 'x11' => [ - ['account_id' => 'account-x11', 'product' => 'Desk'], - ], - ] - */ - - -#### `has()` {#collection-method} - -The `has` method determines if a given key exists in the collection: - - $collection = collect(['account_id' => 1, 'product' => 'Desk']); - - $collection->has('email'); - - // false - - -#### `implode()` {#collection-method} - -The `implode` method joins the items in a collection. Its arguments depend on the type of items in the collection. If the collection contains arrays or objects, you should pass the key of the attributes you wish to join, and the "glue" string you wish to place between the values: - - $collection = collect([ - ['account_id' => 1, 'product' => 'Desk'], - ['account_id' => 2, 'product' => 'Chair'], - ]); - - $collection->implode('product', ', '); - - // Desk, Chair - -If the collection contains simple strings or numeric values, simply pass the "glue" as the only argument to the method: - - collect([1, 2, 3, 4, 5])->implode('-'); - - // '1-2-3-4-5' - - -#### `intersect()` {#collection-method} - -The `intersect` method removes any values from the original collection that are not present in the given `array` or collection. The resulting collection will preserve the original collection's keys: - - $collection = collect(['Desk', 'Sofa', 'Chair']); - - $intersect = $collection->intersect(['Desk', 'Chair', 'Bookcase']); - - $intersect->all(); - - // [0 => 'Desk', 2 => 'Chair'] - - -#### `isEmpty()` {#collection-method} - -The `isEmpty` method returns `true` if the collection is empty; otherwise, `false` is returned: - - collect([])->isEmpty(); - - // true - - -#### `keyBy()` {#collection-method} - -The `keyBy` method keys the collection by the given key. If multiple items have the same key, only the last one will appear in the new collection: - - $collection = collect([ - ['product_id' => 'prod-100', 'name' => 'desk'], - ['product_id' => 'prod-200', 'name' => 'chair'], - ]); - - $keyed = $collection->keyBy('product_id'); - - $keyed->all(); - - /* - [ - 'prod-100' => ['product_id' => 'prod-100', 'name' => 'Desk'], - 'prod-200' => ['product_id' => 'prod-200', 'name' => 'Chair'], - ] - */ - -You may also pass a callback to the method. The callback should return the value to key the collection by: - - $keyed = $collection->keyBy(function ($item) { - return strtoupper($item['product_id']); - }); - - $keyed->all(); - - /* - [ - 'PROD-100' => ['product_id' => 'prod-100', 'name' => 'Desk'], - 'PROD-200' => ['product_id' => 'prod-200', 'name' => 'Chair'], - ] - */ - - - -#### `keys()` {#collection-method} - -The `keys` method returns all of the collection's keys: - - $collection = collect([ - 'prod-100' => ['product_id' => 'prod-100', 'name' => 'Desk'], - 'prod-200' => ['product_id' => 'prod-200', 'name' => 'Chair'], - ]); - - $keys = $collection->keys(); - - $keys->all(); - - // ['prod-100', 'prod-200'] - - -#### `last()` {#collection-method} - -The `last` method returns the last element in the collection that passes a given truth test: - - collect([1, 2, 3, 4])->last(function ($value, $key) { - return $value < 3; - }); - - // 2 - -You may also call the `last` method with no arguments to get the last element in the collection. If the collection is empty, `null` is returned: - - collect([1, 2, 3, 4])->last(); - - // 4 - - -#### `map()` {#collection-method} - -The `map` method iterates through the collection and passes each value to the given callback. The callback is free to modify the item and return it, thus forming a new collection of modified items: - - $collection = collect([1, 2, 3, 4, 5]); - - $multiplied = $collection->map(function ($item, $key) { - return $item * 2; - }); - - $multiplied->all(); - - // [2, 4, 6, 8, 10] - -> {note} Like most other collection methods, `map` returns a new collection instance; it does not modify the collection it is called on. If you want to transform the original collection, use the [`transform`](#method-transform) method. - - -#### `max()` {#collection-method} - -The `max` method return the maximum value of a given key: - - $max = collect([['foo' => 10], ['foo' => 20]])->max('foo'); - - // 20 - - $max = collect([1, 2, 3, 4, 5])->max(); - - // 5 - - -#### `merge()` {#collection-method} - -The `merge` method merges the given array into the original collection. If a string key in the given array matches a string key in the original collection, the given array's value will overwrite the value in the original collection: - - $collection = collect(['product_id' => 1, 'price' => 100]); - - $merged = $collection->merge(['price' => 200, 'discount' => false]); - - $merged->all(); - - // ['product_id' => 1, price' => 200, 'discount' => false] - -If the given array's keys are numeric, the values will be appended to the end of the collection: - - $collection = collect(['Desk', 'Chair']); - - $merged = $collection->merge(['Bookcase', 'Door']); - - $merged->all(); - - // ['Desk', 'Chair', 'Bookcase', 'Door'] - - -#### `min()` {#collection-method} - -The `min` method return the minimum value of a given key: - - $min = collect([['foo' => 10], ['foo' => 20]])->min('foo'); - - // 10 - - $min = collect([1, 2, 3, 4, 5])->min(); - - // 1 - - -#### `only()` {#collection-method} - -The `only` method returns the items in the collection with the specified keys: - - $collection = collect(['product_id' => 1, 'name' => 'Desk', 'price' => 100, 'discount' => false]); - - $filtered = $collection->only(['product_id', 'name']); - - $filtered->all(); - - // ['product_id' => 1, 'name' => 'Desk'] - -For the inverse of `only`, see the [except](#method-except) method. - - -#### `pluck()` {#collection-method} - -The `pluck` method retrieves all of the values for a given key: - - $collection = collect([ - ['product_id' => 'prod-100', 'name' => 'Desk'], - ['product_id' => 'prod-200', 'name' => 'Chair'], - ]); - - $plucked = $collection->pluck('name'); - - $plucked->all(); - - // ['Desk', 'Chair'] - -You may also specify how you wish the resulting collection to be keyed: - - $plucked = $collection->pluck('name', 'product_id'); - - $plucked->all(); - - // ['prod-100' => 'Desk', 'prod-200' => 'Chair'] - - -#### `pop()` {#collection-method} - -The `pop` method removes and returns the last item from the collection: - - $collection = collect([1, 2, 3, 4, 5]); - - $collection->pop(); - - // 5 - - $collection->all(); - - // [1, 2, 3, 4] - - -#### `prepend()` {#collection-method} - -The `prepend` method adds an item to the beginning of the collection: - - $collection = collect([1, 2, 3, 4, 5]); - - $collection->prepend(0); - - $collection->all(); - - // [0, 1, 2, 3, 4, 5] - -You may also pass a second argument to set the key of the prepended item: - - $collection = collect(['one' => 1, 'two', => 2]); - - $collection->prepend(0, 'zero'); - - $collection->all(); - - // ['zero' => 0, 'one' => 1, 'two', => 2] - - -#### `pull()` {#collection-method} - -The `pull` method removes and returns an item from the collection by its key: - - $collection = collect(['product_id' => 'prod-100', 'name' => 'Desk']); - - $collection->pull('name'); - - // 'Desk' - - $collection->all(); - - // ['product_id' => 'prod-100'] - - -#### `push()` {#collection-method} - -The `push` method appends an item to the end of the collection: - - $collection = collect([1, 2, 3, 4]); - - $collection->push(5); - - $collection->all(); - - // [1, 2, 3, 4, 5] - - -#### `put()` {#collection-method} - -The `put` method sets the given key and value in the collection: - - $collection = collect(['product_id' => 1, 'name' => 'Desk']); - - $collection->put('price', 100); - - $collection->all(); - - // ['product_id' => 1, 'name' => 'Desk', 'price' => 100] - - -#### `random()` {#collection-method} - -The `random` method returns a random item from the collection: - - $collection = collect([1, 2, 3, 4, 5]); - - $collection->random(); - - // 4 - (retrieved randomly) - -You may optionally pass an integer to `random` to specify how many items you would like to randomly retrieve. If that integer is more than `1`, a collection of items is returned: - - $random = $collection->random(3); - - $random->all(); - - // [2, 4, 5] - (retrieved randomly) - - -#### `reduce()` {#collection-method} - -The `reduce` method reduces the collection to a single value, passing the result of each iteration into the subsequent iteration: - - $collection = collect([1, 2, 3]); - - $total = $collection->reduce(function ($carry, $item) { - return $carry + $item; - }); - - // 6 - -The value for `$carry` on the first iteration is `null`; however, you may specify its initial value by passing a second argument to `reduce`: - - $collection->reduce(function ($carry, $item) { - return $carry + $item; - }, 4); - - // 10 - - -#### `reject()` {#collection-method} - -The `reject` method filters the collection using the given callback. The callback should return `true` if the item should be removed from the resulting collection: - - $collection = collect([1, 2, 3, 4]); - - $filtered = $collection->reject(function ($value, $key) { - return $value > 2; - }); - - $filtered->all(); - - // [1, 2] - -For the inverse of the `reject` method, see the [`filter`](#method-filter) method. - - -#### `reverse()` {#collection-method} - -The `reverse` method reverses the order of the collection's items: - - $collection = collect([1, 2, 3, 4, 5]); - - $reversed = $collection->reverse(); - - $reversed->all(); - - // [5, 4, 3, 2, 1] - - -#### `search()` {#collection-method} - -The `search` method searches the collection for the given value and returns its key if found. If the item is not found, `false` is returned. - - $collection = collect([2, 4, 6, 8]); - - $collection->search(4); - - // 1 - -The search is done using a "loose" comparison, meaning a string with an integer value will be considered equal to an integer of the same value. To use strict comparison, pass `true` as the second argument to the method: - - $collection->search('4', true); - - // false - -Alternatively, you may pass in your own callback to search for the first item that passes your truth test: - - $collection->search(function ($item, $key) { - return $item > 5; - }); - - // 2 - - -#### `shift()` {#collection-method} - -The `shift` method removes and returns the first item from the collection: - - $collection = collect([1, 2, 3, 4, 5]); - - $collection->shift(); - - // 1 - - $collection->all(); - - // [2, 3, 4, 5] - - -#### `shuffle()` {#collection-method} - -The `shuffle` method randomly shuffles the items in the collection: - - $collection = collect([1, 2, 3, 4, 5]); - - $shuffled = $collection->shuffle(); - - $shuffled->all(); - - // [3, 2, 5, 1, 4] // (generated randomly) - - -#### `slice()` {#collection-method} - -The `slice` method returns a slice of the collection starting at the given index: - - $collection = collect([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); - - $slice = $collection->slice(4); - - $slice->all(); - - // [5, 6, 7, 8, 9, 10] - -If you would like to limit the size of the returned slice, pass the desired size as the second argument to the method: - - $slice = $collection->slice(4, 2); - - $slice->all(); - - // [5, 6] - -The returned slice will preserve keys by default. If you do not wish to preserve the original keys, you can use the `values` method to reindex them. - - -#### `sort()` {#collection-method} - -The `sort` method sorts the collection. The sorted collection keeps the original array keys, so in this example we'll use the [`values`](#method-values) method to reset the keys to consecutively numbered indexes: - - $collection = collect([5, 3, 1, 2, 4]); - - $sorted = $collection->sort(); - - $sorted->values()->all(); - - // [1, 2, 3, 4, 5] - -If your sorting needs are more advanced, you may pass a callback to `sort` with your own algorithm. Refer to the PHP documentation on [`usort`](http://php.net/manual/en/function.usort.php#refsect1-function.usort-parameters), which is what the collection's `sort` method calls under the hood. - -> {tip} If you need to sort a collection of nested arrays or objects, see the [`sortBy`](#method-sortby) and [`sortByDesc`](#method-sortbydesc) methods. - - -#### `sortBy()` {#collection-method} - -The `sortBy` method sorts the collection by the given key. The sorted collection keeps the original array keys, so in this example we'll use the [`values`](#method-values) method to reset the keys to consecutively numbered indexes: - - $collection = collect([ - ['name' => 'Desk', 'price' => 200], - ['name' => 'Chair', 'price' => 100], - ['name' => 'Bookcase', 'price' => 150], - ]); - - $sorted = $collection->sortBy('price'); - - $sorted->values()->all(); - - /* - [ - ['name' => 'Chair', 'price' => 100], - ['name' => 'Bookcase', 'price' => 150], - ['name' => 'Desk', 'price' => 200], - ] - */ - -You can also pass your own callback to determine how to sort the collection values: - - $collection = collect([ - ['name' => 'Desk', 'colors' => ['Black', 'Mahogany']], - ['name' => 'Chair', 'colors' => ['Black']], - ['name' => 'Bookcase', 'colors' => ['Red', 'Beige', 'Brown']], - ]); - - $sorted = $collection->sortBy(function ($product, $key) { - return count($product['colors']); - }); - - $sorted->values()->all(); - - /* - [ - ['name' => 'Chair', 'colors' => ['Black']], - ['name' => 'Desk', 'colors' => ['Black', 'Mahogany']], - ['name' => 'Bookcase', 'colors' => ['Red', 'Beige', 'Brown']], - ] - */ - - -#### `sortByDesc()` {#collection-method} - -This method has the same signature as the [`sortBy`](#method-sortby) method, but will sort the collection in the opposite order. - - -#### `splice()` {#collection-method} - -The `splice` method removes and returns a slice of items starting at the specified index: - - $collection = collect([1, 2, 3, 4, 5]); - - $chunk = $collection->splice(2); - - $chunk->all(); - - // [3, 4, 5] - - $collection->all(); - - // [1, 2] - -You may pass a second argument to limit the size of the resulting chunk: - - $collection = collect([1, 2, 3, 4, 5]); - - $chunk = $collection->splice(2, 1); - - $chunk->all(); - - // [3] - - $collection->all(); - - // [1, 2, 4, 5] - -In addition, you can pass a third argument containing the new items to replace the items removed from the collection: - - $collection = collect([1, 2, 3, 4, 5]); - - $chunk = $collection->splice(2, 1, [10, 11]); - - $chunk->all(); - - // [3] - - $collection->all(); - - // [1, 2, 10, 11, 4, 5] - - -#### `sum()` {#collection-method} - -The `sum` method returns the sum of all items in the collection: - - collect([1, 2, 3, 4, 5])->sum(); - - // 15 - -If the collection contains nested arrays or objects, you should pass a key to use for determining which values to sum: - - $collection = collect([ - ['name' => 'JavaScript: The Good Parts', 'pages' => 176], - ['name' => 'JavaScript: The Definitive Guide', 'pages' => 1096], - ]); - - $collection->sum('pages'); - - // 1272 - -In addition, you may pass your own callback to determine which values of the collection to sum: - - $collection = collect([ - ['name' => 'Chair', 'colors' => ['Black']], - ['name' => 'Desk', 'colors' => ['Black', 'Mahogany']], - ['name' => 'Bookcase', 'colors' => ['Red', 'Beige', 'Brown']], - ]); - - $collection->sum(function ($product) { - return count($product['colors']); - }); - - // 6 - - -#### `take()` {#collection-method} - -The `take` method returns a new collection with the specified number of items: - - $collection = collect([0, 1, 2, 3, 4, 5]); - - $chunk = $collection->take(3); - - $chunk->all(); - - // [0, 1, 2] - -You may also pass a negative integer to take the specified amount of items from the end of the collection: - - $collection = collect([0, 1, 2, 3, 4, 5]); - - $chunk = $collection->take(-2); - - $chunk->all(); - - // [4, 5] - - -#### `toArray()` {#collection-method} - -The `toArray` method converts the collection into a plain PHP `array`. If the collection's values are [Eloquent](/docs/{{version}}/eloquent) models, the models will also be converted to arrays: - - $collection = collect(['name' => 'Desk', 'price' => 200]); - - $collection->toArray(); - - /* - [ - ['name' => 'Desk', 'price' => 200], - ] - */ - -> {note} `toArray` also converts all of the collection's nested objects to an array. If you want to get the raw underlying array, use the [`all`](#method-all) method instead. - - -#### `toJson()` {#collection-method} - -The `toJson` method converts the collection into JSON: - - $collection = collect(['name' => 'Desk', 'price' => 200]); - - $collection->toJson(); - - // '{"name":"Desk","price":200}' - - -#### `transform()` {#collection-method} - -The `transform` method iterates over the collection and calls the given callback with each item in the collection. The items in the collection will be replaced by the values returned by the callback: - - $collection = collect([1, 2, 3, 4, 5]); - - $collection->transform(function ($item, $key) { - return $item * 2; - }); - - $collection->all(); - - // [2, 4, 6, 8, 10] - -> {note} Unlike most other collection methods, `transform` modifies the collection itself. If you wish to create a new collection instead, use the [`map`](#method-map) method. - - -#### `union()` {#collection-method} - -The `union` method adds the given array to the collection. If the given array contains keys that are already in the original collection, the original collection's values will be preferred: - - $collection = collect([1 => ['a'], 2 => ['b']]); - - $union = $collection->union([3 => ['c'], 1 => ['b']]); - - $union->all(); - - // [1 => ['a'], 2 => ['b'], [3 => ['c']] - - -#### `unique()` {#collection-method} - -The `unique` method returns all of the unique items in the collection. The returned collection keeps the original array keys, so in this example we'll use the [`values`](#method-values) method to reset the keys to consecutively numbered indexes: - - $collection = collect([1, 1, 2, 2, 3, 4, 2]); - - $unique = $collection->unique(); - - $unique->values()->all(); - - // [1, 2, 3, 4] - -When dealing with nested arrays or objects, you may specify the key used to determine uniqueness: - - $collection = collect([ - ['name' => 'iPhone 6', 'brand' => 'Apple', 'type' => 'phone'], - ['name' => 'iPhone 5', 'brand' => 'Apple', 'type' => 'phone'], - ['name' => 'Apple Watch', 'brand' => 'Apple', 'type' => 'watch'], - ['name' => 'Galaxy S6', 'brand' => 'Samsung', 'type' => 'phone'], - ['name' => 'Galaxy Gear', 'brand' => 'Samsung', 'type' => 'watch'], - ]); - - $unique = $collection->unique('brand'); - - $unique->values()->all(); - - /* - [ - ['name' => 'iPhone 6', 'brand' => 'Apple', 'type' => 'phone'], - ['name' => 'Galaxy S6', 'brand' => 'Samsung', 'type' => 'phone'], - ] - */ - -You may also pass your own callback to determine item uniqueness: - - $unique = $collection->unique(function ($item) { - return $item['brand'].$item['type']; - }); - - $unique->values()->all(); - - /* - [ - ['name' => 'iPhone 6', 'brand' => 'Apple', 'type' => 'phone'], - ['name' => 'Apple Watch', 'brand' => 'Apple', 'type' => 'watch'], - ['name' => 'Galaxy S6', 'brand' => 'Samsung', 'type' => 'phone'], - ['name' => 'Galaxy Gear', 'brand' => 'Samsung', 'type' => 'watch'], - ] - */ - - -#### `values()` {#collection-method} - -The `values` method returns a new collection with the keys reset to consecutive integers: - - $collection = collect([ - 10 => ['product' => 'Desk', 'price' => 200], - 11 => ['product' => 'Desk', 'price' => 200] - ]); - - $values = $collection->values(); - - $values->all(); - - /* - [ - 0 => ['product' => 'Desk', 'price' => 200], - 1 => ['product' => 'Desk', 'price' => 200], - ] - */ - -#### `where()` {#collection-method} - -The `where` method filters the collection by a given key / value pair: - - $collection = collect([ - ['product' => 'Desk', 'price' => 200], - ['product' => 'Chair', 'price' => 100], - ['product' => 'Bookcase', 'price' => 150], - ['product' => 'Door', 'price' => 100], - ]); - - $filtered = $collection->where('price', 100); - - $filtered->all(); - - /* - [ - ['product' => 'Chair', 'price' => 100], - ['product' => 'Door', 'price' => 100], - ] - */ - -The `where` method uses loose comparisons when checking item values. Use the [`whereStrict`](#method-wherestrict) method to filter using "strict" comparisons. - - -#### `whereStrict()` {#collection-method} - -This method has the same signature as the [`where`](#method-where) method; however, all values are compared using "strict" comparisons. - - -#### `whereIn()` {#collection-method} - -The `whereIn` method filters the collection by a given key / value contained within the given array. - - $collection = collect([ - ['product' => 'Desk', 'price' => 200], - ['product' => 'Chair', 'price' => 100], - ['product' => 'Bookcase', 'price' => 150], - ['product' => 'Door', 'price' => 100], - ]); - - $filtered = $collection->whereIn('price', [150, 200]); - - $filtered->all(); - - /* - [ - ['product' => 'Bookcase', 'price' => 150], - ['product' => 'Desk', 'price' => 200], - ] - */ - -The `whereIn` method uses strict comparisons when checking item values. Use the [`whereInLoose`](#method-whereinloose) method to filter using "loose" comparisons. - - -#### `whereInLoose()` {#collection-method} - -This method has the same signature as the [`whereIn`](#method-wherein) method; however, all values are compared using "loose" comparisons. - - -#### `zip()` {#collection-method} - -The `zip` method merges together the values of the given array with the values of the original collection at the corresponding index: - - $collection = collect(['Chair', 'Desk']); - - $zipped = $collection->zip([100, 200]); - - $zipped->all(); - - // [['Chair', 100], ['Desk', 200]] diff --git a/commands.md b/commands.md new file mode 100644 index 0000000..80f6b86 --- /dev/null +++ b/commands.md @@ -0,0 +1,142 @@ +# Artisan Development + +- [Introduction](#introduction) +- [Building A Command](#building-a-command) +- [Registering Commands](#registering-commands) +- [Calling Other Commands](#calling-other-commands) + + +## Introduction + +သင့် application အတွက် ကိုယ်ပိုင် commands တွေကို Artisan နဲ့ ထပ်ပြီးပေါင်းထည့်နိုင်ဖို့စီစဉ်ထားပါတယ်။ သင့်ရဲ့ ကိုယ်ပိုင် command တွေကို `app/commands` မှာထက်ထည့်နိုင်ပါတယ်၊ သို့သော်လည်းသင့်ရဲ့ကိုယ်ပိုင် command တွေကို သင်ကြိုက်တဲ့ storage location မှာ ထည့်နိုင်ပါတယ် သင့်ရဲ့ commands တွေကို သင့်ရဲ့ `composer.json` settings မှာအခြေခံပြီး autoload လုပ်နိုင်ပါတယ်။ + + +## Building A Command + +### Generating The Class + +command တစ်ခုအသစ် create လုပ်ရန်အတွက် - သင့်အနေနဲ့ `command:make` Artisan command ကိုသုံးနိုင်ပါတယ်၊ အဲ့ဒါကသင်စတင်ဖို့ command stub တစ်ခုကို generate ထုတ်ပေးပါလိမ့်မယ်: + +#### Generate A New Command Class + + php artisan command:make FooCommand + +Default အရ generate လုပ်လိုက်တဲ့ commands တွေက `app/commands` မှာ သိမ်းဆည်းထားမှာပါ... သို့သော်လည်း သင့်ကိုယ်ပိုင် path ဒါမှမဟုတ် namespace တစ်ခု သတ်မှတ်ထားလို့လည်းရပါတယ်: + + php artisan command:make FooCommand --path=app/classes --namespace=Classes + +command create လုပ်တဲ့အချိန်မှာ `--command` option ကို terminal command name အဖြစ် assign လုပ်ရန်အသုံးပြုပါလိမ့်မယ်: + + php artisan command:make AssignUsers --command=users:assign + +### Writing The Command + +သင့်ရဲ့ command generate လုပ်ပြီးသွားတဲ့အချိန်မှာ သင့်အနေနဲ့ `name` နဲ့ `description` တွေရဲ့ class properties တွေကို ဖြည့်စွတ်သင့်ပါတယ်၊ အဲဒါတွေက သင့်ရဲ့ command တွေကို `list` နဲ့ screen မှာထုတ်ပြတဲ့အချိန်မှာ အသုံးပြုမှာပါ။ + +သင့် command excute ဖြစ်သွားပြီဆိုရင် `fire` method ကိုခေါ်ပါ့မယ်။ ဒီ method မှာသင်ကြိုက်တဲ့ command logic ကိုထည့်နိုင်တယ်။ + +### Arguments & Options + +The `getArguments` and `getOptions` methods are where you may define any arguments or options your command receives. + +`getArguments` နဲ့ `getOptions` methods တွေကို သင့် command ကနေလက်ခံရရှိတဲ့ မည်သည့် arguments ဒါမှမဟုတ် options မဆို သတ်မှတ်နိုင်ပါတယ်။ ဒီ methods နှစ်ခုက commands တွေကို array တစ်ခု return ပြန်ပါတယ်၊ အဲ့ဒီ့ array က array options တွေကို list တစ်ခုပုံစံနဲ့ ဖော်ပြထားပါတယ်။ + +`arguments` တွေကို defining လုပ်တဲ့အချိန်မှာ array definition values တွေကို အောက်မှာပြထားသလိုကိုယ်စားပြုပါတယ် - + + array($name, $mode, $description, $defaultValue) + +argument `mode` တွေက `InputArgument::REQUIRED` or `InputArgument::OPTIONAL` တစ်ခုခုဖြစ်လိမ့်မယ်။ + +`options` တွေကိုသတ်မှတ်တဲ့အချိန်မှာ array definition values တွေကို အောက်မှာပြထားသလိုကိုယ်စားပြုပါတယ် - + + array($name, $shortcut, $mode, $description, $defaultValue) + +options အတွက်... argument `mode` က `InputOption::VALUE_REQUIRED`, `InputOption::VALUE_OPTIONAL`, `InputOption::VALUE_IS_ARRAY`, `InputOption::VALUE_NONE` တွေဖြစ်လိမ့်မယ်။ + +`VALUES_IS_ARRAY` mode ကဘာကိုပြောတာလဲဆိုရင် command ကိုခေါ်တဲ့အချိန်မှာ နှစ်ကြိမ်သုံးလို့ရတယ်ဆိုတာကိုပြတာပါ - + + php artisan foo --option=bar --option=baz + +The `VALUE_NONE` option indicates that the option is simply used as a "switch": +`VALUE_NONE` ကဘာကိုပြောတာလဲဆိုရင် သင့်ရဲ့ option ကို "switch" အဖြစ်ရိုးရှင်းစွာ သုံးလို့ရတယ်ဆိုတာကိုပြတာပါ - + + php artisan foo --option + +### Retrieving Input + +ဘာလို့ သင့်ရဲ့ command က execute ဖြစ်တာလည်း၊ သင်သေချာပေါက် arguments နဲ့ options တွေကို application က accept လုပ်လိုက် တဲ့ values access လုပ်ဖို့လိုပါမယ် လို့ပါမယ် ဒါကိုလုပ်ဖို့ဆိုရင် သင့်အနေနဲ့ `argument` နဲ့ `option` method တွေကိုသုံးဖို့လိုပါလိမ့်မယ်။ + +#### Retrieving The Value Of A Command Argument + + $value = $this->argument('name'); + +#### Retrieving All Arguments + + $arguments = $this->argument(); + +#### Retrieving The Value Of A Command Option + + $value = $this->option('name'); + +#### Retrieving All Options + + $options = $this->option(); + +### Writing Output + +To send output to the console, you may use the `info`, `comment`, `question` and `error` methods. Each of these methods will use the appropriate ANSI colors for their purpose. + +Console ဆီကို output send ဖို့ရာအတွက် သင့်အနေနဲ့ `info`, `comment`, `question` နဲ့ `error` methods တွေကိုအသုံးပြုဖို့လိုပါလိမ့်မယ်။ ဒီ methods တစ်ခုချင်းဆီက သူတို့ရည်ရွယ်ချက်နဲ့သင့်လျော်တဲ့ ANSI colors တွေကို အသုံးပြုပါလိမ့်မယ်။ + +#### Sending Information To The Console + + $this->info('Display this on the screen'); + +#### Sending An Error Message To The Console + + $this->error('Something went wrong!'); + +### Asking Questions + +user input prompt အတွက် သင့်အနေနဲ့ `ask` နဲ့ `confirm` methods တွေကို အသုံးပြုနိုင်ပါတယ် - + +#### Asking The User For Input + + $name = $this->ask('What is your name?'); + +#### Asking The User For Secret Input + + $password = $this->secret('What is the password?'); + +#### Asking The User For Confirmation + + if ($this->confirm('Do you wish to continue? [yes|no]')) + { + // + } + +သင့်အနေနဲ့ default value ကိုု `confirm` method အဖြစ် သတ်မှတ်ထားနိုင်ပါတယ်၊ ဒါက `true` or `false` ဖြစ်သင့်ပါတယ်: + + $this->confirm($question, true); + + +## Registering Commands + +#### Registering An Artisan Command + +သင်ရဲ့ command ကပြီးသွားပြီ ဆိုရင် သင့်အနေနဲ့ Artisan နဲ့ register လုပ်ရပါမယ် ဒါမှ အသုံးပြုလို့ရမှာပါ။ ဒါကိုလည်း ထုံးစံအတိုင်းဘဲ `app/start/artisan.php` file မှာ လုပ်ရမှာပါ။ ဒီ file ထဲမှာ command ကို register လုပ်ဖို့ရာအတွက် `Artisan::add` method ကို အသုံးပြုသင့်ပါတယ် - + + Artisan::add(new CustomCommand); + +#### Registering A Command That Is In The IoC Container + +သင့် ရဲ့ command က application ရဲ့ [IoC container](ioc.md) ထဲမှာ Register လုပ်ထားတယ်ဆိုရင်... Arisan ကနေခေါ်နိုင်အောင် သင့်အနေဲ့ `Artisan::resolve` method ကို အသုံးပြုရပါ့မယ် - + + Artisan::resolve('binding.name'); + + +## Calling Other Commands + +တစ်ခါတစ်လေသင့် command ကနေအခြား command တစ်ခုခုကိုခေါ်ချင်မှာပေါ့... ဒါလည်းရပါတယ် `call` method နဲ့ခေါ်လိုက်ရုံပါဘဲ - + + $this->call('command:name', array('argument' => 'foo', '--option' => 'bar')); \ No newline at end of file diff --git a/configuration.md b/configuration.md index d681f80..f885f96 100644 --- a/configuration.md +++ b/configuration.md @@ -1,96 +1,146 @@ -# Configuration +# Configuration လုပ်ခြင်း -- [Introduction](#introduction) -- [Accessing Configuration Values](#accessing-configuration-values) -- [Environment Configuration](#environment-configuration) - - [Determining The Current Environment](#determining-the-current-environment) -- [Configuration Caching](#configuration-caching) -- [Maintenance Mode](#maintenance-mode) +- [မိတ်ဆက်](#introduction) +- [Environment ပြင်ဆင်ခြင်း](#environment-configuration) +- [Provider ပြင်ဆင်ခြင်း](#provider-configuration) +- [အမှားခံ၊ အသိခံ၍ မရသော အချက်အလက်များအား ကာကွယ်ခြင်း](#protecting-sensitive-configuration) +- [Application အားပြုပြင်ထိန်းသိမ်းမှု အခြေအနေ](#maintenance-mode) -## Introduction +## မိတ်ဆက် -All of the configuration files for the Laravel framework are stored in the `config` directory. Each option is documented, so feel free to look through the files and get familiar with the options available to you. +Laravel framework မှာရှိတဲ့ configuration ဖိုင်အားလုံးကို `app/config` လမ်းကြောင်းအောက်မှာသိမ်းထားပါတယ်။ ဖိုင်အားလုံးမှာပါတဲ့ option တစ်ခုချင်းစီအတွက် documentation မှာ ရေးထားပီးသားပါ။ အသုံးပြုနိုင်တဲ့ options တွေကို documentation နဲ့တွဲပြီး လေ့လာ နိုင်ပါတယ်။ - -## Accessing Configuration Values +Application run နေတဲ့အချိန်တွေမှာ configuration values တွေကို အသုံးပြုဖို့လိုအပ်လာရင် `Config` class ကိုအသုံးပြုပြီး ဆွဲယူနိုင်ပါတယ်။ -You may easily access your configuration values using the global `config` helper function from anywhere in your application. The configuration values may be accessed using "dot" syntax, which includes the name of the file and option you wish to access. A default value may also be specified and will be returned if the configuration option does not exist: +#### Configuration Value များကို အသုံးပြုခြင်း - $value = config('app.timezone'); + Config::get('app.timezone'); -To set configuration values at runtime, pass an array to the `config` helper: +ဆွဲယူအသုံးပြုလိုက်တဲ့ configuration option မရှိတဲ့အခြေအနေအတွက် default value ကို return ပြန်အောင် သတ်မှတ်ပေးထားနိုင်ပါတယ်။ - config(['app.timezone' => 'America/Chicago']); + $timezone = Config::get('app.timezone', 'UTC'); + +#### Configuration value သတ်မှတ်ခြင်း + +Configuration ဖိုင်တွေထဲမှာရှိတဲ့ value တွေကို "dot” ကိုအသုံးပြုပြီး (eg. filename.value) access လုပ်နိုင်ပါတယ်။ Application run-time ကာလမှာ configuration တွေသတ်မှတ်ဖို့အတွက်လည်း အသုံးပြုနိုင်ပါတယ်။ + + Config::set('database.default', 'sqlite'); + +Applicastion run-time ကာလမှာ သတ်မှတ်ထားတဲ့ configuration values တွေဟာ app ရဲ့ လက်ရှိ request အပေါ်မှာပဲသက်ရောက်မှုရှိပါတယ်။ နောက်ပိုင်းထပ်ဖြစ်လာမဲ့ requests တွေအထိ ယူဆောင်သွားမှာမဟုတ်ပါဘူး -## Environment Configuration +## Environment ပြင်ဆင်ခြင်း -It is often helpful to have different configuration values based on the environment the application is running in. For example, you may wish to use a different cache driver locally than you do on your production server. +Application run နေတဲ့ environment အပေါ်အခြေခံပီး configuration ဖိုင်တွေ သတ်မှတ်ထားခြင်းဟာ အထောက်အကူ အများကြီးဖြစ်စေပါတယ်။ ဥပမာ - ကိုယ့်ရဲ့ local machine ပေါ်မှာ မတူညီတဲ့ cache driver တွေအသုံးပြုချင်တယ်ဆိုရင် ဒီ environment based configuration ကိုအသုံးပြုရုံနဲ့ လွယ်ကူ ပြီးမြောက်စေနိုင်ပါတယ်။ -To make this a cinch, Laravel utilizes the [DotEnv](https://github.com/vlucas/phpdotenv) PHP library by Vance Lucas. In a fresh Laravel installation, the root directory of your application will contain a `.env.example` file. If you install Laravel via Composer, this file will automatically be renamed to `.env`. Otherwise, you should rename the file manually. +`config` ဖိုဒါထဲမှာ ကိုယ့်ရဲ့ environmen လိုက်ဖက်မဲ့ directory တစ်ခုကို ဆောက်လိုက်ပါ။ ဥပမာ - `local`။ ပြီးရင် အဲ့ဒီ environment အတွက် override လုပ်သွားမဲ့ config တွေ၊ ထပ်မံသတ်မှတ်ချင်တဲ့ options တွေကို configuration ဖိုင်တွေပြုလုပ်ပီးသတ်မှတ်နိုင်ပါပြီ။ ဥပမာ - local environment အတွက် cache driver ကို override လုပ်ချင်တယ်ဆိုရင်၊ `app/config/local` ဖိုဒါထဲမှာ `cache.php` ဖိုင်ဆောက်ပီး အောက်မှာပေးထားတဲ့ code တွေနဲ့ ပြုလုပ်လိုက်ပါ။ -#### Retrieving Environment Configuration + env('APP_DEBUG', false), + 'driver' => 'file', -The second value passed to the `env` function is the "default value". This value will be used if no environment variable exists for the given key. + ); -Your `.env` file should not be committed to your application's source control, since each developer / server using your application could require a different environment configuration. +> **သတိပြုရန်:** `testing` ဆိုတဲ့ အမည်နဲ့ environment name ကို မသတ်မှတ်ပါနဲ့။ အဲ့ဒီအမည်ဟာ unit testing အတွက် သီးသန့်သတ်မှတ်ထားတဲ့ အမည်ဖြစ်ပါတယ်။ -If you are developing with a team, you may wish to continue including a `.env.example` file with your application. By putting place-holder values in the example configuration file, other developers on your team can clearly see which environment variables are needed to run your application. +base configuration ဖိုင်မှာပါတဲ့ option အားလုံးကို ပြန်လည်သတ်မှတ်ပေးဖို့ မလိုအပ်ပါ လိုအပ်ပြီး ကိုယ့်အနေနဲ့ override လုပ်ချင်တဲ့ option တွေကိုသာသတ်မှတ်ပေးရန်။ Base configuration files တွေကို environment configuration files တွေက "cascade” လုပ်သွားပါလိမ့်မယ်။ - -### Determining The Current Environment +ပြီးရင်တော့ ဘယ် environment မှာ run နေတယ်ဆိုတာ framework ကနေ သိနိုင်ဖို့အတွက် သတ်မှတ်ထားပေးရမှာပါ။ Default environment ကတော့ `production` ဖြစ်ပါတယ်။ အခြား environment တွေအတွက် setup ပြုလုပ်ရမဲ့ နေရာက root directory အောက်မှာရှိတဲ့ `bootstrap/start.php` ဖိုင်ထဲမှာပြုလုပ်ပေးရပါမယ်။ အဲ့ဒီဖိုင်ထဲမှာရှိတဲ့ `$app->detectEnvironment` ဆိုတဲ့ method ထဲကို သတ်မှတ်ထားတဲ့ environment တွေပါတဲ့ array တစ်ခု passing လုပ်ထားပါတယ်။ အဲ့ဒီ array ကိုအသုံးပြုပြီး လက်ရှိ environment ကို ဆုံးဖြတ်တာဖြစ်ပါတယ်။ လိုအပ်လာလို့ရှိရင် အဲ့ဒီ array ထဲကို နောက်ထပ် environment တွေ ထပ်ထည့်နိုင်ပါတယ်။ -The current application environment is determined via the `APP_ENV` variable from your `.env` file. You may access this value via the `environment` method on the `App` [facade](/docs/{{version}}/facades): + detectEnvironment(array( -You may also pass arguments to the `environment` method to check if the environment matches a given value. The method will return `true` if the environment matches any of the given values: + 'local' => array('your-machine-name'), - if (App::environment('local')) { - // The environment is local - } + )); - if (App::environment('local', 'staging')) { - // The environment is either local OR staging... - } +အပေါ်မှာပြထားတဲ့ ဥပမာမှာ `local` က environment အမည်ဖြစ်ပြီး `your-machine-name` က server ရဲ့ hostname ဖြစ်ပါတယ်။ Linux နဲ့ Mac ကွန်ပျူတာတွေမှာဆိုရင် `hostname` ဆိုတဲ့ terminal command ကိုအသုံးပြုပြီး hostname ကိုသတ်မှတ်ပေးနိုင်ပါတယ်။ - -## Configuration Caching +အကယ်၍ ပိုပြီးထိရောက်တဲ့ environment သိရှိမှုကို လိုအပ်တယ်ဆိုရင်တော့ `detectEnvironment` method ထဲကို ကိုယ်လိုအပ်သလိုအသုံးပြုနိုင်တဲ့ environment သိရှိမှုတွေကိုပြုလုပ်ပေးနိုင်မဲ့ `Closure` တစ်ခုကို passing ပေးဖို့လိုအပ်ပါတယ်။ -To give your application a speed boost, you should cache all of your configuration files into a single file using the `config:cache` Artisan command. This will combine all of the configuration options for your application into a single file which will be loaded quickly by the framework. + $env = $app->detectEnvironment(function() + { + return $_SERVER['MY_LARAVEL_ENV']; + }); -You should typically run the `php artisan config:cache` command as part of your production deployment routine. The command should not be run during local development as configuration options will frequently need to be changed during the course of your application's development. +#### Application ရဲ့ လက်ရှိ Environment ကိုအသုံးပြုခြင်း။ - -## Maintenance Mode +Application ရဲ့ လက်ရှိအသုံးပြုနေတဲ့ environment ကို `environment` method ကိုအသုံးပြုပြီး ရယူနိုင်ပါတယ်။ + + $environment = App::environment(); + +ကိုယ်အသုံးပြုချင်တဲ့ environment ဟုတ်/မဟုတ် ကိုလည်း `environment` method ထဲကို arguments တွေ passing ပေးပြီး စစ်ကြည့်နိုင်ပါတယ်။ + + if (App::environment('local')) + { + // Local environment ဖြစ်တယ် + } + + if (App::environment('local', 'staging')) + { + //Local သို့မဟုတ် staging environment ဖြစ်တယ် + } + + +### Provider ပြင်ဆင်ခြင်း + +Environment configuration ကို အသုံးပြုပြီဆိုလို့ရှိရင်၊ ကိုယ့်ရဲ့ ပင်မ `app` configuration ဖိုင်ထဲမှာ environment [service providers](ioc#service-providers.md) ကိုထည့်ပေါင်းထည့်ဖို့ လိုအပ်လာတဲ့ အခြေအနေတွေ ရှိလာနိုင်ပါတယ်။ အကယ်၍ ကိုယ်က ထပ်ပေါင်းထည့်ထားတယ်ဆိုလို့ရှိရင်, the environment `app` providers are overriding the providers in your primary `app` configuration file ဆိုပြီး သတိပေးပါလိမ့်မယ်။ အဲ့လိုအခြေအနေမျိုးမှာ providers ကို မရမကထပ်ပေါင်းထည့်စေဖို့အတွက် `append_config` ဆိုတဲ့ helper method ကို ကိုယ့်ရဲ့ environment `app` configuration ဖိုင်ထဲမှာ အသုံးပြုနိုင်ပါတယ်။ + + 'providers' => append_config(array( + 'LocalOnlyServiceProvider', + )) -When your application is in maintenance mode, a custom view will be displayed for all requests into your application. This makes it easy to "disable" your application while it is updating or when you are performing maintenance. A maintenance mode check is included in the default middleware stack for your application. If the application is in maintenance mode, a `MaintenanceModeException` will be thrown with a status code of 503. + +## အမှားခံ၊ အသိခံ၍ မရသော အချက်အလက်များအား ကာကွယ်ခြင်း -To enable maintenance mode, simply execute the `down` Artisan command: +အမှန်တကယ်အသုံးပြုမဲ့ application တွေအတွက်၊ ကိုယ့်ရဲ့ အမှားမခံ၊ အသိခံလို့ မရတဲ့ configuration တွေကို configuration ဖိုင်ထဲမှာ မသိမ်းပဲနဲ့ အခြားတစ်နေရာမှာထားတာက ပိုပြီးသင့်တော်ပါတယ်။ ဘယ်လိုအမျိုးအစားတွေလဲဆိုတော့ database passwords, Stripe API keys, and encryption keys စတာတွေကို ဖြစ်နိုင်လို့ရှိရင် configuration ဖိုင်ထဲမှာမသိမ်းသင့်ပါဘူး။ ဒါဆိုဘယ်နေရာမှာသိမ်းမလဲ? အဲ့ဒီအတွက် Laravel ကဖြေရှင်းပေးပြီးသားဖြစ်ပါတယ်။ အဲ့ဒီလို configuration အမျိုးအစားတွေအတွက် "dot" files တွေကိုအသုံးပြုပြီး ကာကွယ်ထားနိုင်ပါတယ်။ - php artisan down +ပထမဆုံးအနေနဲ့ ကိုယ့်ရဲ့စက်ဟာ local မှာ run နေတာပါဆိုတာကို application ကသိအောင် [configure](configuration#environment-configuration.md) လုပ်ပေးရပါမယ်။ ပြီးရင် `.env.local.php` ဆိုတဲ့ ဖိုင်အသစ်ကို `composer.json` ဖိုင်ရှိတဲ့ ဖိုဒါအောက်မှာ ဆောက်ပေးလိုက်ပါ။ အဲ့ဒီ `.env.local.php` ဖိုင်ဟာ အခြား laravel configuration ဖိုင်တွေလိုပဲ key-value pairs ဖြစ်တဲ့ array တစ်ခု return ပြန်ရပါမယ်။ + + 'super-secret-sauce', + + ); + +အဲ့ဒီ ဖိုင်ထဲကနေ return ပြန်လာတဲ့ key-value pairs တွေဟာ PHP "superglobals" တွေဖြစ်တဲ့ `$_ENV` နဲ့ `$_SERVER` တွေဆီကို auto ရောက်သွားပါလိမ့်မယ်။ အဲ့ဒီ "superglobals" တွေကနေတစ်ဆင့် ကိုယ့်ရဲ့ configuration ဖိုင်ထဲမှာ ပြန်လည်အသုံးပြုနိုင်ပြီဖြစ်ပါတယ်။ + + 'key' => $_ENV['TEST_STRIPE_KEY'] + +သေချာအောင်လုပ်ဖို့လိုအပ်တာတစ်ခုက အဲ့ဒီ `.env.local.php` ဖိုင်ကို `.gitignore` လုပ်ထားပေးရပါမယ်။ အဲ့ဒီတော့မှ ကိုယ့်ရဲ့ team မှာရှိတဲ့ကျန်တဲ့ developers တွေဟာ သူတို့ရဲ့ ကိုယ်ပိုင် local configuration တွေကိုပြုလုပ်နိုင်မည့်အပြင် ကိုယ့်ရဲ့ sensitive configuration တွေကိုလဲ source control မှာမပါအောင် ကာကွယ်ပြီးသားဖြစ်မှာပါ။ + +Production environment အတွက်လည်း လိုအပ်တဲ့ configuration တွေပါတဲ့ `.env.php` ဖိုင်ကို project root ဖိုဒါထဲမှာ ဆောက်လိုက်ပါ။ `.env.local.php` ဖိုင်လိုပဲ production environment မှာ အသုံးပြုမဲ့`.env.php` ဖိုင်ဟာ source control ထဲမှာ မပါသင့်ပါဘူး။ + +> **သတိပြုရန်:** Application ကနေ support လုပ်တဲ့ environment တစ်ခုချင်းစီအတွက် `.env` ဖိုင်တွေ တည်ဆောက်လာနိုင်ပါတယ်။ ဥပမာ - `development` environment အတွက်ဆိုရင် `.env.development.php` ဖိုင်က ရှိနေလို့ရှိရင် load လုပ်သွားပါလိမ့်မယ်။ + + +## Application အားပြုပြင်ထိန်းသိမ်းမှုအခြေအနေ -You may also provide `message` and `retry` options to the `down` command. The `message` value may be used to display or log a custom message, while the `retry` value will be set as the `Retry-After` HTTP header's value: +Application ဟာ ပြုပြင်ထိန်းသိမ်းမှု ပြုလုပ်တဲ့ အခြေအနေမှာ ရှိနေမယ်ဆိုရင် application မှာရှိတဲ့ route အားလုံးအတွက် ကြိုတင်ပြုလုပ်ထားနိုင်တဲ့ စိတ်ကြိုက် မြင်ကွင်း(view) ကိုပြပေးပါလိမ့်မယ်။ ပြုပြင်ထိန်းသိမ်းမှုပြုလုပ်နေရင်ပဲဖြစ်ဖြစ်၊ update လုပ်နေရင်ပဲဖြစ်ဖြစ် application ကို လွယ်လွယ်ကူကူပဲ disable လုပ်ထားနိုင်ပါတယ်။ `app/start/global.php` ဖိုင်ထဲမှာရှိပြီးသားဖြစ်တဲ့ `App::down` ဆိုတဲ့ method ကိုခေါ်သုံးလိုက်ရုံပဲ။ အဲ့ဒီ method ကနေပြန်လာတဲ့ response ကို users တွေဆီကိုပို့ပေးပါလိမ့်မယ်။ - php artisan down --message='Upgrading Database' --retry=60 +ပြုပြင်ထိန်းသိမ်းမှုပြုလုပ်နေပါတယ်ဆိုတဲ့ အခြေအနေကိုထားချင်တယ်ဆိုရင် `down` ဆိုတဲ့ Artisan command ကို အသုံးပြုနိုင်ပါတယ်။ -To disable maintenance mode, use the `up` command: + php artisan down - php artisan up +ထိန်းသိမ်းမှုပြုလုပ်ပြီးသွားလို့ application ကိုပြန်ပြီး အသက်သွင်းချင်ရင် `up` ဆိုတဲ့ Artisan command ကို အသုံးပြုနိုင်ပါတယ်။ -#### Maintenance Mode Response Template + php artisan up -The default template for maintenance mode responses is located in `resources/views/errors/503.blade.php`. You are free to modify this view as needed for your application. +ထိန်းသိမ်းမှုပြုလုပ်နေတဲ့အခြေအနေအတွက် စိတ်ကြိုက် မြင်ကွင်း (view) သတ်မှတ်ချင်တယ်ဆိုရင်တော့ အောက်မှာပြထားသလိုပဲ `app/start/global.php` ဖိုင်ထဲမှာ နှစ်သက်သလို သွားရောက်ပြင်ဆင်နိုင်ပါတယ်။ -#### Maintenance Mode & Queues + App::down(function() + { + return Response::view('maintenance', array(), 503); + }); -While your application is in maintenance mode, no [queued jobs](/docs/{{version}}/queues) will be handled. The jobs will continue to be handled as normal once the application is out of maintenance mode. +အကယ်၍ `down` method ထဲကို Closure တစ်ခု passing ပေးလိုက်ရင်တော့ `NULL` ပဲ return ပြန်လာပြီး အဲ့ဒီ request မှာပါတဲ့ maintenance mode ကို ignore လုပ်သွားပါလိမ့်မယ်။ -#### Alternatives To Maintenance Mode +### Maintenance Mode နှင့် Queues -Since maintenance mode requires your application to have several seconds of downtime, consider alternatives like [Envoyer](https://envoyer.io) to accomplish zero-downtime deployment with Laravel. +Application ဟာ maintenance mode မှာ ရှိနေစဉ်အတွင်း [queue jobs](queues.md) တွေကို ကိုင်တွယ်ဖြေရှင်းမှာမဟုတ်ပါဘူး။ Application ဟာ ပုံမှန်အခြေအနေ ကိုပြန်ရောက်ပီဆိုတော့မှ ပြန်လည်ကိုင်တွယ်ဖြေရှင်းပေးမှာဖြစ်ပါတယ်။ \ No newline at end of file diff --git a/container.md b/container.md deleted file mode 100644 index 3b4bbe1..0000000 --- a/container.md +++ /dev/null @@ -1,249 +0,0 @@ -# Service Container - -- [Introduction](#introduction) -- [Binding](#binding) - - [Binding Basics](#binding-basics) - - [Binding Interfaces To Implementations](#binding-interfaces-to-implementations) - - [Contextual Binding](#contextual-binding) - - [Tagging](#tagging) -- [Resolving](#resolving) - - [The Make Method](#the-make-method) - - [Automatic Injection](#automatic-injection) -- [Container Events](#container-events) - - -## Introduction - -The Laravel service container is a powerful tool for managing class dependencies and performing dependency injection. Dependency injection is a fancy phrase that essentially means this: class dependencies are "injected" into the class via the constructor or, in some cases, "setter" methods. - -Let's look at a simple example: - - users = $users; - } - - /** - * Show the profile for the given user. - * - * @param int $id - * @return Response - */ - public function show($id) - { - $user = $this->users->find($id); - - return view('user.profile', ['user' => $user]); - } - } - -In this example, the `UserController` needs to retrieve users from a data source. So, we will **inject** a service that is able to retrieve users. In this context, our `UserRepository` most likely uses [Eloquent](/docs/{{version}}/eloquent) to retrieve user information from the database. However, since the repository is injected, we are able to easily swap it out with another implementation. We are also able to easily "mock", or create a dummy implementation of the `UserRepository` when testing our application. - -A deep understanding of the Laravel service container is essential to building a powerful, large application, as well as for contributing to the Laravel core itself. - - -## Binding - - -### Binding Basics - -Almost all of your service container bindings will be registered within [service providers](/docs/{{version}}/providers), so most of these examples will demonstrate using the container in that context. - -> {tip} There is no need to bind classes into the container if they do not depend on any interfaces. The container does not need to be instructed on how to build these objects, since it can automatically resolve these objects using reflection. - -#### Simple Bindings - -Within a service provider, you always have access to the container via the `$this->app` property. We can register a binding using the `bind` method, passing the class or interface name that we wish to register along with a `Closure` that returns an instance of the class: - - $this->app->bind('HelpSpot\API', function ($app) { - return new HelpSpot\API($app->make('HttpClient')); - }); - -Note that we receive the container itself as an argument to the resolver. We can then use the container to resolve sub-dependencies of the object we are building. - -#### Binding A Singleton - -The `singleton` method binds a class or interface into the container that should only be resolved one time. Once a singleton binding is resolved, the same object instance will be returned on subsequent calls into the container: - - $this->app->singleton('HelpSpot\API', function ($app) { - return new HelpSpot\API($app->make('HttpClient')); - }); - -#### Binding Instances - -You may also bind an existing object instance into the container using the `instance` method. The given instance will always be returned on subsequent calls into the container: - - $api = new HelpSpot\API(new HttpClient); - - $this->app->instance('HelpSpot\Api', $api); - -#### Binding Primitives - -Sometimes you may have a class that receives some injected classes, but also needs an injected primitive value such as an integer. You may easily use contextual binding to inject any value your class may need: - - $this->app->when('App\Http\Controllers\UserController') - ->needs('$variableName') - ->give($value); - - -### Binding Interfaces To Implementations - -A very powerful feature of the service container is its ability to bind an interface to a given implementation. For example, let's assume we have an `EventPusher` interface and a `RedisEventPusher` implementation. Once we have coded our `RedisEventPusher` implementation of this interface, we can register it with the service container like so: - - $this->app->bind( - 'App\Contracts\EventPusher', - 'App\Services\RedisEventPusher' - ); - -This statement tells the container that it should inject the `RedisEventPusher` when a class needs an implementation of `EventPusher`. Now we can type-hint the `EventPusher` interface in a constructor, or any other location where dependencies are injected by the service container: - - use App\Contracts\EventPusher; - - /** - * Create a new class instance. - * - * @param EventPusher $pusher - * @return void - */ - public function __construct(EventPusher $pusher) - { - $this->pusher = $pusher; - } - - -### Contextual Binding - -Sometimes you may have two classes that utilize the same interface, but you wish to inject different implementations into each class. For example, two controllers may depend on different implementations of the `Illuminate\Contracts\Filesystem\Filesystem` [contract](/docs/{{version}}/contracts). Laravel provides a simple, fluent interface for defining this behavior: - - use Illuminate\Support\Facades\Storage; - use App\Http\Controllers\PhotoController; - use App\Http\Controllers\VideoController; - use Illuminate\Contracts\Filesystem\Filesystem; - - $this->app->when(PhotoController::class) - ->needs(Filesystem::class) - ->give(function () { - return Storage::disk('local'); - }); - - $this->app->when(VideoController::class) - ->needs(Filesystem::class) - ->give(function () { - return Storage::disk('s3'); - }); - - -### Tagging - -Occasionally, you may need to resolve all of a certain "category" of binding. For example, perhaps you are building a report aggregator that receives an array of many different `Report` interface implementations. After registering the `Report` implementations, you can assign them a tag using the `tag` method: - - $this->app->bind('SpeedReport', function () { - // - }); - - $this->app->bind('MemoryReport', function () { - // - }); - - $this->app->tag(['SpeedReport', 'MemoryReport'], 'reports'); - -Once the services have been tagged, you may easily resolve them all via the `tagged` method: - - $this->app->bind('ReportAggregator', function ($app) { - return new ReportAggregator($app->tagged('reports')); - }); - - -## Resolving - - -#### The `make` Method - -You may use the `make` method to resolve a class instance out of the container. The `make` method accepts the name of the class or interface you wish to resolve: - - $api = $this->app->make('HelpSpot\API'); - -If you are in a location of your code that does not have access to the `$app` variable, you may use the global `app` helper: - - $api = app('HelpSpot\API'); - - -#### Automatic Injection - -Alternatively, and importantly, you may simply "type-hint" the dependency in the constructor of a class that is resolved by the container, including [controllers](/docs/{{version}}/controllers), [event listeners](/docs/{{version}}/events), [queue jobs](/docs/{{version}}/queues), [middleware](/docs/{{version}}/middleware), and more. In practice, this is how most of your objects should be resolved by the container. - -For example, you may type-hint a repository defined by your application in a controller's constructor. The repository will automatically be resolved and injected into the class: - - users = $users; - } - - /** - * Show the user with the given ID. - * - * @param int $id - * @return Response - */ - public function show($id) - { - // - } - } - - -## Container Events - -The service container fires an event each time it resolves an object. You may listen to this event using the `resolving` method: - - $this->app->resolving(function ($object, $app) { - // Called when container resolves object of any type... - }); - - $this->app->resolving(HelpSpot\API::class, function ($api, $app) { - // Called when container resolves objects of type "HelpSpot\API"... - }); - -As you can see, the object being resolved will be passed to the callback, allowing you to set any additional properties on the object before it is given to its consumer. diff --git a/contracts.md b/contracts.md deleted file mode 100644 index 8803e40..0000000 --- a/contracts.md +++ /dev/null @@ -1,205 +0,0 @@ -# Contracts - -- [Introduction](#introduction) - - [Contracts Vs. Facades](#contracts-vs-facades) -- [When To Use Contracts](#when-to-use-contracts) - - [Loose Coupling](#loose-coupling) - - [Simplicity](#simplicity) -- [How To Use Contracts](#how-to-use-contracts) -- [Contract Reference](#contract-reference) - - -## Introduction - -Laravel's Contracts are a set of interfaces that define the core services provided by the framework. For example, a `Illuminate\Contracts\Queue\Queue` contract defines the methods needed for queueing jobs, while the `Illuminate\Contracts\Mail\Mailer` contract defines the methods needed for sending e-mail. - -Each contract has a corresponding implementation provided by the framework. For example, Laravel provides a queue implementation with a variety of drivers, and a mailer implementation that is powered by [SwiftMailer](http://swiftmailer.org/). - -All of the Laravel contracts live in [their own GitHub repository](https://github.com/illuminate/contracts). This provides a quick reference point for all available contracts, as well as a single, decoupled package that may be utilized by package developers. - - -### Contracts Vs. Facades - -Laravel's [facades](/docs/{{version}}/facades) and helper functions provide a simple way of utilizing Laravel's services without needing to type-hint and resolve contracts out of the service container. In most cases, each facade has an equivalent contract. - -Unlike facades, which do not require you to require them in your class' constructor, contracts allow you to define explicit dependencies for your classes. Some developers prefer to explicitly define their dependencies in this way and therefore prefer to use contracts, while other developers enjoy the convenience of facades. - -> {tip} Most applications will be fine regardless of whether you prefer facades or contracts. However, if you are building a package, you should strongly consider using contracts since they will be easier to test in a package context. - - -## When To Use Contracts - -As discussed elsewhere, much of the decision to use contracts or facades will come down to personal taste and the tastes of your development team. Both contracts and facades can be used to create robust, well-tested Laravel applications. As long as you are keeping your class' responsibilities focused, you will notice very few practical differences between using contracts and facades. - -However, you may still have several questions regarding contracts. For example, why use interfaces at all? Isn't using interfaces more complicated? Let's distil the reasons for using interfaces to the following headings: loose coupling and simplicity. - - -### Loose Coupling - -First, let's review some code that is tightly coupled to a cache implementation. Consider the following: - - cache = $cache; - } - - /** - * Retrieve an Order by ID. - * - * @param int $id - * @return Order - */ - public function find($id) - { - if ($this->cache->has($id)) { - // - } - } - } - -In this class, the code is tightly coupled to a given cache implementation. It is tightly coupled because we are depending on a concrete Cache class from a package vendor. If the API of that package changes our code must change as well. - -Likewise, if we want to replace our underlying cache technology (Memcached) with another technology (Redis), we again will have to modify our repository. Our repository should not have so much knowledge regarding who is providing them data or how they are providing it. - -**Instead of this approach, we can improve our code by depending on a simple, vendor agnostic interface:** - - cache = $cache; - } - } - -Now the code is not coupled to any specific vendor, or even Laravel. Since the contracts package contains no implementation and no dependencies, you may easily write an alternative implementation of any given contract, allowing you to replace your cache implementation without modifying any of your cache consuming code. - - -### Simplicity - -When all of Laravel's services are neatly defined within simple interfaces, it is very easy to determine the functionality offered by a given service. **The contracts serve as succinct documentation to the framework's features.** - -In addition, when you depend on simple interfaces, your code is easier to understand and maintain. Rather than tracking down which methods are available to you within a large, complicated class, you can refer to a simple, clean interface. - - -## How To Use Contracts - -So, how do you get an implementation of a contract? It's actually quite simple. - -Many types of classes in Laravel are resolved through the [service container](/docs/{{version}}/container), including controllers, event listeners, middleware, queued jobs, and even route Closures. So, to get an implementation of a contract, you can just "type-hint" the interface in the constructor of the class being resolved. - -For example, take a look at this event listener: - - redis = $redis; - } - - /** - * Handle the event. - * - * @param OrderWasPlaced $event - * @return void - */ - public function handle(OrderWasPlaced $event) - { - // - } - } - -When the event listener is resolved, the service container will read the type-hints on the constructor of the class, and inject the appropriate value. To learn more about registering things in the service container, check out [its documentation](/docs/{{version}}/container). - - -## Contract Reference - -This table provides a quick reference to all of the Laravel contracts and their equivalent facades: - -Contract | References Facade -------------- | ------------- -[Illuminate\Contracts\Auth\Factory](https://github.com/illuminate/contracts/blob/master/Auth/Factory.php) | Auth -[Illuminate\Contracts\Auth\PasswordBroker](https://github.com/illuminate/contracts/blob/master/Auth/PasswordBroker.php) | Password -[Illuminate\Contracts\Bus\Dispatcher](https://github.com/illuminate/contracts/blob/master/Bus/Dispatcher.php) | Bus -[Illuminate\Contracts\Broadcasting\Broadcaster](https://github.com/illuminate/contracts/blob/master/Broadcasting/Broadcaster.php) |   -[Illuminate\Contracts\Cache\Repository](https://github.com/illuminate/contracts/blob/master/Cache/Repository.php) | Cache -[Illuminate\Contracts\Cache\Factory](https://github.com/illuminate/contracts/blob/master/Cache/Factory.php) | Cache::driver() -[Illuminate\Contracts\Config\Repository](https://github.com/illuminate/contracts/blob/master/Config/Repository.php) | Config -[Illuminate\Contracts\Container\Container](https://github.com/illuminate/contracts/blob/master/Container/Container.php) | App -[Illuminate\Contracts\Cookie\Factory](https://github.com/illuminate/contracts/blob/master/Cookie/Factory.php) | Cookie -[Illuminate\Contracts\Cookie\QueueingFactory](https://github.com/illuminate/contracts/blob/master/Cookie/QueueingFactory.php) | Cookie::queue() -[Illuminate\Contracts\Encryption\Encrypter](https://github.com/illuminate/contracts/blob/master/Encryption/Encrypter.php) | Crypt -[Illuminate\Contracts\Events\Dispatcher](https://github.com/illuminate/contracts/blob/master/Events/Dispatcher.php) | Event -[Illuminate\Contracts\Filesystem\Cloud](https://github.com/illuminate/contracts/blob/master/Filesystem/Cloud.php) |   -[Illuminate\Contracts\Filesystem\Factory](https://github.com/illuminate/contracts/blob/master/Filesystem/Factory.php) | File -[Illuminate\Contracts\Filesystem\Filesystem](https://github.com/illuminate/contracts/blob/master/Filesystem/Filesystem.php) | File -[Illuminate\Contracts\Foundation\Application](https://github.com/illuminate/contracts/blob/master/Foundation/Application.php) | App -[Illuminate\Contracts\Hashing\Hasher](https://github.com/illuminate/contracts/blob/master/Hashing/Hasher.php) | Hash -[Illuminate\Contracts\Logging\Log](https://github.com/illuminate/contracts/blob/master/Logging/Log.php) | Log -[Illuminate\Contracts\Mail\MailQueue](https://github.com/illuminate/contracts/blob/master/Mail/MailQueue.php) | Mail::queue() -[Illuminate\Contracts\Mail\Mailer](https://github.com/illuminate/contracts/blob/master/Mail/Mailer.php) | Mail -[Illuminate\Contracts\Queue\Factory](https://github.com/illuminate/contracts/blob/master/Queue/Factory.php) | Queue::driver() -[Illuminate\Contracts\Queue\Queue](https://github.com/illuminate/contracts/blob/master/Queue/Queue.php) | Queue -[Illuminate\Contracts\Redis\Database](https://github.com/illuminate/contracts/blob/master/Redis/Database.php) | Redis -[Illuminate\Contracts\Routing\Registrar](https://github.com/illuminate/contracts/blob/master/Routing/Registrar.php) | Route -[Illuminate\Contracts\Routing\ResponseFactory](https://github.com/illuminate/contracts/blob/master/Routing/ResponseFactory.php) | Response -[Illuminate\Contracts\Routing\UrlGenerator](https://github.com/illuminate/contracts/blob/master/Routing/UrlGenerator.php) | URL -[Illuminate\Contracts\Support\Arrayable](https://github.com/illuminate/contracts/blob/master/Support/Arrayable.php) |   -[Illuminate\Contracts\Support\Jsonable](https://github.com/illuminate/contracts/blob/master/Support/Jsonable.php) |   -[Illuminate\Contracts\Support\Renderable](https://github.com/illuminate/contracts/blob/master/Support/Renderable.php) |   -[Illuminate\Contracts\Validation\Factory](https://github.com/illuminate/contracts/blob/master/Validation/Factory.php) | Validator::make() -[Illuminate\Contracts\Validation\Validator](https://github.com/illuminate/contracts/blob/master/Validation/Validator.php) |   -[Illuminate\Contracts\View\Factory](https://github.com/illuminate/contracts/blob/master/View/Factory.php) | View::make() -[Illuminate\Contracts\View\View](https://github.com/illuminate/contracts/blob/master/View/View.php) |   diff --git a/contributing.md b/contributing.md index e68c3d3..f7af0d9 100644 --- a/contributing.md +++ b/contributing.md @@ -1,3 +1,17 @@ -# Contribution Guidelines +# ပူးပေါင်းပါဝင်မှု လမ်းညွန် -If you are submitting documentation for the **current stable release**, submit it to the corresponding branch. For example, documentation for Laravel 5.1 would be submitted to the `5.1` branch. Documentation intended for the next release of Laravel should be submitted to the `master` branch. \ No newline at end of file +###ဘာသာပြန်ခြင်း + + - ကျွန်တော်တို့ကို ပူးပေါင်းပါဝင် ကူညီပြီးဘာသာပြန်ချင်တယ်ဆိုရင် + [docs](https://github.com/Laravel-Myanmar/docs) ကိုဦးစွာ Fork လုပ်ပါ၊ + + - ဘယ်အပိုင်းကို ဘာသာပြန်မည်ဆိုတာကို [Facebook](https://www.facebook.com/groups/250409601822202/) မှာပြောပေးပါ။ (Fork + လုပ်ပြီးဘာသာပြန်နေတုန်းအခြားတစ်ယောက်ယောက်ကပါဘာသာပြန်နေတာမျိုးဖြစ်မှာစိုးလို့ပါ) + + - သင်ဘာသာပြန်မည့် File ကိုဘာသာပြန်ပါ။ ဘာသာပြန်ပြီးရင် မူရင်း repo ဆီက + [pull request](https://github.com/Laravel-Myanmar/docs/pulls) တောင်းပါ။ (pull request တောင်းတာကို မြန်မြန် accept + လုပ်စေချင်တယ်ဆိုရင်[Facebook]( https://www.facebook.com/groups/250409601822202/) မှာပါတင်ပေးပါ) + +###ဘာသာပြန်အဆင်ပြေမှူနှင့် စာလုံးပေါင်းအမှား + +ဘာသာပြန်ထားတာတွေ ကိုဦးစွာဖတ်ပါ။ ဘာသာပြန်အဆင်ပြေမှူ နဲ့ စာလုံးပေါင်း အမှားတွေကို စစ်ပါ။ ဘာသာပြန်အဆင်ပြေမှူမရှိတာတို့ စာလုံးပေါင်းအမှားတွေတွေ့ရင် GitHub မှာ [issue](https://github.com/Laravel-Myanmar/docs/issues) တင်ပေးပါ။(အမှားတွေကို အမြန်ဆုံး စစ်ပေးဖို့ [Facebook](https://www.facebook.com/groups/250409601822202/) မှာပါတင်ပေးပါ) diff --git a/contributions.md b/contributions.md deleted file mode 100644 index fd80e2c..0000000 --- a/contributions.md +++ /dev/null @@ -1,82 +0,0 @@ -# Contribution Guide - -- [Bug Reports](#bug-reports) -- [Core Development Discussion](#core-development-discussion) -- [Which Branch?](#which-branch) -- [Security Vulnerabilities](#security-vulnerabilities) -- [Coding Style](#coding-style) - - [PHPDoc](#phpdoc) - - [StyleCI](#styleci) - - -## Bug Reports - -To encourage active collaboration, Laravel strongly encourages pull requests, not just bug reports. "Bug reports" may also be sent in the form of a pull request containing a failing test. - -However, if you file a bug report, your issue should contain a title and a clear description of the issue. You should also include as much relevant information as possible and a code sample that demonstrates the issue. The goal of a bug report is to make it easy for yourself - and others - to replicate the bug and develop a fix. - -Remember, bug reports are created in the hope that others with the same problem will be able to collaborate with you on solving it. Do not expect that the bug report will automatically see any activity or that others will jump to fix it. Creating a bug report serves to help yourself and others start on the path of fixing the problem. - -The Laravel source code is managed on Github, and there are repositories for each of the Laravel projects: - -- [Laravel Framework](https://github.com/laravel/framework) -- [Laravel Application](https://github.com/laravel/laravel) -- [Laravel Documentation](https://github.com/laravel/docs) -- [Laravel Cashier](https://github.com/laravel/cashier) -- [Laravel Cashier for Braintree](https://github.com/laravel/cashier-braintree) -- [Laravel Envoy](https://github.com/laravel/envoy) -- [Laravel Homestead](https://github.com/laravel/homestead) -- [Laravel Homestead Build Scripts](https://github.com/laravel/settler) -- [Laravel Website](https://github.com/laravel/laravel.com) -- [Laravel Art](https://github.com/laravel/art) - - -## Core Development Discussion - -You may propose new features or improvements of existing Laravel behavior in the Laravel Internals [issue board](https://github.com/laravel/internals/issues). If you propose a new feature, please be willing to implement at least some of the code that would be needed to complete the feature. - -Informal discussion regarding bugs, new features, and implementation of existing features takes place in the `#internals` channel of the [LaraChat](http://larachat.co) Slack team. Taylor Otwell, the maintainer of Laravel, is typically present in the channel on weekdays from 8am-5pm (UTC-06:00 or America/Chicago), and sporadically present in the channel at other times. - - -## Which Branch? - -**All** bug fixes should be sent to the latest stable branch or to the current LTS branch (5.1). Bug fixes should **never** be sent to the `master` branch unless they fix features that exist only in the upcoming release. - -**Minor** features that are **fully backwards compatible** with the current Laravel release may be sent to the latest stable branch. - -**Major** new features should always be sent to the `master` branch, which contains the upcoming Laravel release. - -If you are unsure if your feature qualifies as a major or minor, please ask Taylor Otwell in the `#internals` channel of the [LaraChat](http://larachat.co) Slack team. - - -## Security Vulnerabilities - -If you discover a security vulnerability within Laravel, please send an email to Taylor Otwell at taylor@laravel.com. All security vulnerabilities will be promptly addressed. - - -## Coding Style - -Laravel follows the [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) coding standard and the [PSR-4](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md) autoloading standard. - - -### PHPDoc - -Below is an example of a valid Laravel documentation block. Note that the `@param` attribute is followed by two spaces, the argument type, two more spaces, and finally the variable name: - - /** - * Register a binding with the container. - * - * @param string|array $abstract - * @param \Closure|string|null $concrete - * @param bool $shared - * @return void - */ - public function bind($abstract, $concrete = null, $shared = false) - { - // - } - - -### StyleCI - -Don't worry if your code styling isn't perfect! [StyleCI](https://styleci.io/) will automatically merge any style fixes into the Laravel repository after pull requests are merged. This allows us to focus on the content of the contribution and not the code style. diff --git a/controllers.md b/controllers.md index 402f2fb..066c1ab 100644 --- a/controllers.md +++ b/controllers.md @@ -1,305 +1,224 @@ -# Controllers +# Controllers များအကြောင်း -- [Introduction](#introduction) - [Basic Controllers](#basic-controllers) - - [Defining Controllers](#defining-controllers) - - [Controllers & Namespaces](#controllers-and-namespaces) - - [Single Action Controllers](#single-action-controllers) -- [Controller Middleware](#controller-middleware) +- [Controller Filters](#controller-filters) +- [RESTful Controllers](#restful-controllers) - [Resource Controllers](#resource-controllers) - - [Partial Resource Routes](#restful-partial-resource-routes) - - [Naming Resource Routes](#restful-naming-resource-routes) - - [Naming Resource Route Parameters](#restful-naming-resource-route-parameters) - - [Supplementing Resource Controllers](#restful-supplementing-resource-controllers) -- [Dependency Injection & Controllers](#dependency-injection-and-controllers) -- [Route Caching](#route-caching) - - -## Introduction - -Instead of defining all of your request handling logic as Closures in route files, you may wish to organize this behavior using Controller classes. Controllers can group related request handling logic into a single class. Controllers are stored in the `app/Http/Controllers` directory. +- [Handling Missing Methods](#handling-missing-methods) ## Basic Controllers - -### Defining Controllers - -Below is an example of a basic controller class. Note that the controller extends the base controller class included with Laravel. The base class provides a few convenience methods such as the `middleware` method, which may be used to attach middleware to controller actions: - - User::findOrFail($id)]); - } - } - -You can define a route to this controller action like so: +Application ရဲ့ Route ပိုင်းဆိုင်ရာအာလုံးကို `routes.php` တဖိုင်တည်းမှာ အားလုံး သတ်မှတ်ထားသလို ၊ အဲဒီ route တွေရဲ့ Action အားလုံးကို Controller က Class တွေနဲ့ ထိန်းချုပ်နိုင်မှာပါ။ Controllers က routes မှာသတ်မှတ်တဲ့ Action တွေကို ထိန်းချုပ်ပေးယုံ သာမက Framework တခုအတွက် အားသာချက်တခုဖြစ်တဲ့ [Automatic dependency injection][1] တွေပါအသုံးပြုနိုင်မှာပါ။ - Route::get('user/{id}', 'UserController@show'); +Controllers ဖိုင်တွေကို ပုံမှန်အားဖြင့် `app/controllers` အောက်မှာ သိမ်းဆည်းထားပါတယ်။ အဲဒီ Controller ဖိုင်တွေကို `Composer.json` မှာ `Classmap စနစ်ဖြင့်အသုံးပြုထားပါတယ်။ဘယ်လိုပဲဖြစ်ဖြစ် Controllers တွေက Application ရဲ့ ဘယ်နေရာမှာ မဆို အလုပ်လုပ်နိုင်ပါတယ်။ Route မှာ Controllers ကို သိမ်းဆန်းထားတဲ့နေရာအတွက် သတ်မှတ်ချက်တွေက မရှိပါ။ဘာလို့လဲဆိုတော့ Composer က Classmap autoload သုံးပြုထားတဲ့ controller class ကို အလိုလို သိမှတ်ပြုပြီးသားဖြစ်နေလို့ပါ။Controllers ဖိုင်တွေကို နှစ်သက်ရာ နေရာမှာ သိမ်းဆည်းပြီး အလုပ်လုပ်နိုင်ပါတယ်။ -Now, when a request matches the specified route URI, the `show` method on the `UserController` class will be executed. Of course, the route parameters will also be passed to the method. +အခြေခံအားဖြင့် Controller Class တခုရဲ့ ပုံစံက အောက်ပါအတိုင်းရေးသားပါတယ်။ -> {tip} Controllers are not **required** to extend a base class. However, you will not have access to convenience features such as the `middleware`, `validate`, and `dispatch` methods. + class UserController extends BaseController { - -### Controllers & Namespaces + /** + * Show the profile for the given user. + */ + public function showProfile($id) + { + $user = User::find($id); -It is very important to note that we did not need to specify the full controller namespace when defining the controller route. Since the `RouteServiceProvider` loads your route files within a route group that contains the namespace, we only specified the portion of the class name that comes after the `App\Http\Controllers` portion of the namespace. + return View::make('user.profile', array('user' => $user)); + } -If you choose to nest your controllers deeper into the `App\Http\Controllers` directory, simply use the specific class name relative to the `App\Http\Controllers` root namespace. So, if your full controller class is `App\Http\Controllers\Photos\AdminController`, you should register routes to the controller like so: + } - Route::get('foo', 'Photos\AdminController@method'); - -### Single Action Controllers +Controllers တွေအားလုံးက `BaseController` Class ကို ထပ်ကွန့် အသုံးပြုရမှာပါ။ `BaseController` ကိုလဲ `app/controllers` မှာ သိမ်းဆည်းထားပြီး ပြန်လည်အသုံးပြုနိုင်တဲ့ ဖိုင်အနေနဲ့သိမ်းဆည်းထားပါတယ်။`BaseContoller` ဆိုတာက Laravel framework ရဲ့ `Controller` Class ကို ထပ်ကွန့် အသုံးပြုထားပါတယ်။အခုဆိုရင်တော့ Route ဖိုင်မှ တဆင့် အသုံးပြုလိုတဲ့ Controller action ကို အောက်ပါအတိုင်းသတ်မှတ်နိုင်ပါပြီ။ -If you would like to define a controller that only handles a single action, you may place a single `__invoke` method on the controller: + Route::get('user/{id}', 'UserController@showProfile'); - User::findOrFail($id)]); - } - } +> **Note::** အခုချိန်မှာ ကျွန်တော်တို့က PHP classes တွေ ကို autoload အသုံးပြုနိုင်ရန်အတွက် [Composer](http://getcomposer.org) ကို အသုံးပြုထားပါတယ်။ ဒါကြောင့် Controller file ကို System ရဲ့ ဘယ်နေရာမှာပဲထားထား ၊ Composer က အဲဒီ ဖိုင်ကို သိနေသ၍ အသုံးပြုနိုင်မှာပါ။ Controllers ဖိုင်ရဲ့ တည်နေရာကို အတည်တကျ အသေ သတ်မှတ်ထားသလိုမျိုးမရှိပါဘူး။Routing to controllers is entirely de-coupled from the file system. -When registering routes for single action controllers, you do not need to specify a method: - Route::get('user/{id}', 'ShowProfile'); +Controller ကို သတ်မှတ်ထားတဲ့ Route ကို အောက်ကပုံစံအတိုင်း သတ်မှတ်နိုင်ပါတယ်။ - -## Controller Middleware + Route::get('foo', array('uses' => 'FooController@method','as' => 'name')); -[Middleware](/docs/{{version}}/middleware) may be assigned to the controller's routes in your route files: +Controller Action ပါတဲ့ URL ( Link ) တခု ဖန်တီးဖို့အတွက် `URL::action` ဆိုပြီးသုံးပြုနိုင်သလို `action` helper function ကိုလဲ အောက်ပါအတိုင်းသုံးပြုနိုင်ပါတယ်။ - Route::get('profile', 'UserController@show')->middleware('auth'); + $url = URL::action('FooController@method'); -However, it is more convenient to specify middleware within your controller's constructor. Using the `middleware` method from your controller's constructor, you may easily assign middleware to the controller's action. You may even restrict the middleware to only certain methods on the controller class: + $url = action('FooController@method'); - class UserController extends Controller - { - /** - * Instantiate a new new controller instance. - * - * @return void - */ - public function __construct() - { - $this->middleware('auth'); +Controller action တစ်ခုရဲ့ နာမည်ကို သိရန်အတွက် 'currentRouteAction' method ကို အောက်က ပုံစံအတိုင်း အသုံးပြုနိုင်ပါတယ်။ - $this->middleware('log')->only('index'); + $action = Route::currentRouteAction(); - $this->middleware('subscribed')->except('store'); - } - } + +## Controller Filters -> {tip} You may assign middleware to a subset of controller actions; however, it may indicate your controller is growing too large. Instead, consider breaking your controller into multiple, smaller controllers. +[Filters](routing#route-filters.md) က Controller ပါတဲ့ route တခုသတ်မှတ်ကတည်းက အောက်ပါပုံစံအတိုင်း သတ်မှတ်ခဲ့ပါတယ်။ - -## Resource Controllers - -Laravel resource routing assigns the typical "CRUD" routes to a controller with a single line of code. For example, you may wish to create a controller that handles all HTTP requests for "photos" stored by your application. Using the `make:controller` Artisan command, we can quickly create such a controller: - - php artisan make:controller PhotoController --resource + Route::get('profile', array('before' => 'auth', + 'uses' => 'UserController@showProfile')); -This command will generate a controller at `app/Http/Controllers/PhotoController.php`. The controller will contain a method for each of the available resource operations. +နောက်တစ်နည်းက Controller ဖိုင်ထဲရောက်မှ အောက်ကပုံစံအတိုင်းလဲ အသုံးပြုနိုင်ပါတယ်။ -Next, you may register a resourceful route to the controller: + class UserController extends BaseController { - Route::resource('photos', 'PhotoController'); + /** + * Instantiate a new UserController instance. + */ + public function __construct() + { + $this->beforeFilter('auth', array('except' => 'getLogin')); -This single route declaration creates multiple routes to handle a variety of actions on the resource. The generated controller will already have methods stubbed for each of these actions, including notes informing you of the HTTP verbs and URIs they handle. + $this->beforeFilter('csrf', array('on' => 'post')); -#### Actions Handled By Resource Controller + $this->afterFilter('log', array('only' => + array('fooAction', 'barAction'))); + } -Verb | URI | Action | Route Name -----------|-----------------------|--------------|--------------------- -GET | `/photos` | index | photos.index -GET | `/photos/create` | create | photos.create -POST | `/photos` | store | photos.store -GET | `/photos/{photo}` | show | photos.show -GET | `/photos/{photo}/edit` | edit | photos.edit -PUT/PATCH | `/photos/{photo}` | update | photos.update -DELETE | `/photos/{photo}` | destroy | photos.destroy + } -#### Spoofing Form Methods -Since HTML forms can't make `PUT`, `PATCH`, or `DELETE` requests, you will need to add a hidden `_method` field to spoof these HTTP verbs. The `method_field` helper can create this field for you: +You may also specify controller filters inline using a Closure: - {{ method_field('PUT') }} + class UserController extends BaseController { - -### Partial Resource Routes + /** + * Instantiate a new UserController instance. + */ + public function __construct() + { + $this->beforeFilter(function() + { + // + }); + } -When declaring a resource route, you may specify a subset of actions the controller should handle instead of the full set of default actions: + } - Route::resource('photo', 'PhotoController', ['only' => [ - 'index', 'show' - ]]); +Controller တစ်ခုအတွက် Filter ကို သီးခြားအသုံးပြုချင်ရင်တော့ `@` ဆိုတဲ့ syntax ကို အသုံးပြုပြီး အောက်ပါအတိုင်း သတ်မှတ်ပေးရပါတယ်။ - Route::resource('photo', 'PhotoController', ['except' => [ - 'create', 'store', 'update', 'destroy' - ]]); + class UserController extends BaseController { - -### Naming Resource Routes + /** + * Instantiate a new UserController instance. + */ + public function __construct() + { + $this->beforeFilter('@filterRequests'); + } -By default, all resource controller actions have a route name; however, you can override these names by passing a `names` array with your options: + /** + * Filter the incoming requests. + */ + public function filterRequests($route, $request) + { + // + } - Route::resource('photo', 'PhotoController', ['names' => [ - 'create' => 'photo.build' - ]]); + } - -### Naming Resource Route Parameters + -By default, `Route::resource` will create the route parameters for your resource routes based on the "singularized" version of the resource name. You can easily override this on a per resource basis by passing `parameters` in the options array. The `parameters` array should be an associative array of resource names and parameter names: +## RESTful Controllers - Route::resource('user', 'AdminUserController', ['parameters' => [ - 'user' => 'admin_user' - ]]); +Laravel တွင် Controller တွေရဲ့ Action အားလုံးအတွက် REST ဖြင့် Route ကနေ အလွယ်တကူ သတ်မှတ်နိုင်ပါတယ်။ ပထမဆုံး method အတွက် Route ကို 'Route::controller' ဖြင့် သတ်မှတ်ပါ။ - The example above generates the following URIs for the resource's `show` route: + Route::controller('users', 'UserController'); - /user/{admin_user} +`controller` method တွင် arguments နှစ်ခု လက်ခံပါတယ်။ ပထမတခုက Base URL controller handles( ဥပမာ. create, index ) ဖြစ်ပြီး ၊ ဒုတိယတခုကတော့ Controller ရဲ့ နာမည်ဖြစ်ပါတယ်။ နောက်တစ်ခုက Controller တွင် Method(getindex/postprofile)တွေကို HTTP verb အလိုက် ထည့်ပေးရပါမယ်။ - -### Supplementing Resource Controllers + class UserController extends BaseController { -If you need to add additional routes to a resource controller beyond the default set of resource routes, you should define those routes before your call to `Route::resource`; otherwise, the routes defined by the `resource` method may unintentionally take precedence over your supplemental routes: + public function getIndex() + { + // + } - Route::get('photos/popular', 'PhotoController@method'); + public function postProfile() + { + // + } - Route::resource('photos', 'PhotoController'); + } -> {tip} Remember to keep your controllers focused. If you find yourself routinely needing methods outside of the typical set of resource actions, consider splitting your controller into two, smaller controllers. +`index` method က route မှာပေးထားတဲ့ index ကို အလုပ်လုပ်ပါတယ်။ ကျွန်တော်တို့ အပေါ်မှာဆို route name ကို users ဆိုပြီးပေးခဲ့ပါတယ်။ အဲဒါဆိုရင် users လို့ခေါ်ရင် Controller ထဲက index က အလုပ်လုပ်သွားမှာပါ။ - -## Dependency Injection & Controllers +Controller action မှာ စကားစုအများကြီးပါလာသုံးခဲ့ရင် `dash` syntax သုံးနည်းနဲ့ Mathod ကို သတ်မှတ်ပေးရပါတယ်။ ဥပမာ "OurController" ထဲက method တစ်ခု ကို getAdminProfile လို့ပေးထားရင် url ကို `users/admin-profile` လို့ခေါ်လို့ရသွားမှာပါ။ -#### Constructor Injection + public function getAdminProfile() {} -The Laravel [service container](/docs/{{version}}/container) is used to resolve all Laravel controllers. As a result, you are able to type-hint any dependencies your controller may need in its constructor. The declared dependencies will automatically be resolved and injected into the controller instance: + +## Resource Controllers - users = $users; - } - } + Route::resource('photo', 'PhotoController'); -Of course, you may also type-hint any [Laravel contract](/docs/{{version}}/contracts). If the container can resolve it, you can type-hint it. Depending on your application, injecting your dependencies into your controller may provide better testability. -#### Method Injection +အခုဆိုရင် သာမန် Route လေးတစ်ကြောင်းနဲ့ Photo အတွက် RESTful action တစ်ခုရရှိသွားပါပြီ။အခုလိုမျိုးသတ်မှတ်ရုံဖြင့် အောက်ကအတိုင်း Action တွေ အကုန်အသုံးပြုနိုင်သွားပါပြီ။ -In addition to constructor injection, you may also type-hint dependencies on your controller's methods. A common use-case for method injection is injecting the `Illuminate\Http\Request` instance into your controller methods: +#### Actions Handled By Resource Controller - name; + php artisan controller:make PhotoController --except=index - // - } - } -If your controller method is also expecting input from a route parameter, simply list your route arguments after your other dependencies. For example, if your route is defined like so: +ပြီးတော့ Route မှ တဆင့်လဲ လိုအပ်တဲ့ Action တွေ ကို only ကို အသုံးပြုပြီး သတ်မှတ်ပေးသွားနိုင်ပါတယ်။ - Route::put('user/{id}', 'UserController@update'); + Route::resource('photo', 'PhotoController', + array('only' => array('index', 'show'))); -You may still type-hint the `Illuminate\Http\Request` and access your `id` parameter by defining your controller method as follows: + Route::resource('photo', 'PhotoController', + array('except' => array('create', 'store', 'update', 'destroy'))); - array('create' => 'photo.build'))); - use Illuminate\Http\Request; +#### Adding Additional Routes To Resource Controllers - class UserController extends Controller - { - /** - * Update the given user. - * - * @param Request $request - * @param string $id - * @return Response - */ - public function update(Request $request, $id) - { - // - } - } +တကယ်လို့ resource controller မှာ ပုံမှန် routes တွေနဲ့ မလုံလောက်လို့ အသစ်ထပ်ထည့်လို့ရနိုင်ပါသေးတယ်။ အဲဒီ route name ကိုတော့ `Route::resource` ကို မရေးခင်မှာအောက်က ပုံစံအတိုင်း ရေးပေးရပါမယ်။ - -## Route Caching + Route::get('photos/popular'); + Route::resource('photos', 'PhotoController'); -> {note} Closure based routes cannot be cached. To use route caching, you must convert any Closure routes to controller classes. + +## Handling Missing Methods -If your application is exclusively using controller based routes, you should take advantage of Laravel's route cache. Using the route cache will drastically decrease the amount of time it takes to register all of your application's routes. In some cases, your route registration may even be up to 100x faster. To generate a route cache, just execute the `route:cache` Artisan command: +"catch-all method" ဆိုတာက Controller ပေးထားပြီး Mehod မရှိတဲ့အခါမှာ အလုပ်လုပ်မယ့် အခြေအနေဖြစ်ပါတယ်။ Method နာမည်ကိုတော့ "MissingMethod" ဆိုပြီးအောက်ကပုံစံအတိုင်း အသုံးပြုရမှာပါ။ - php artisan route:cache +#### Defining A Catch-All Method -After running this command, your cached routes file will be loaded on every request. Remember, if you add any new routes you will need to generate a fresh route cache. Because of this, you should only run the `route:cache` command during your project's deployment. + public function missingMethod($parameters = array()) + { + // + } -You may use the `route:clear` command to clear the route cache: - php artisan route:clear + [1]: /docs/ioc \ No newline at end of file diff --git a/csrf.md b/csrf.md deleted file mode 100644 index 8f67e03..0000000 --- a/csrf.md +++ /dev/null @@ -1,69 +0,0 @@ -# CSRF Protection - -- [Introduction](#csrf-introduction) -- [Excluding URIs](#csrf-excluding-uris) -- [X-CSRF-Token](#csrf-x-csrf-token) -- [X-XSRF-Token](#csrf-x-xsrf-token) - - -## Introduction - -Laravel makes it easy to protect your application from [cross-site request forgery](http://en.wikipedia.org/wiki/Cross-site_request_forgery) (CSRF) attacks. Cross-site request forgeries are a type of malicious exploit whereby unauthorized commands are performed on behalf of an authenticated user. - -Laravel automatically generates a CSRF "token" for each active user session managed by the application. This token is used to verify that the authenticated user is the one actually making the requests to the application. - -Anytime you define a HTML form in your application, you should include a hidden CSRF token field in the form so that the CSRF protection middleware can validate the request. You may use the `csrf_field` helper to generate the token field: - -
    - {{ csrf_field() }} - ... -
    - -The `VerifyCsrfToken` [middleware](/docs/{{version}}/middleware), which is included in the `web` middleware group, will automatically verify that the token in the request input matches the token stored in the session. - - -## Excluding URIs From CSRF Protection - -Sometimes you may wish to exclude a set of URIs from CSRF protection. For example, if you are using [Stripe](https://stripe.com) to process payments and are utilizing their webhook system, you will need to exclude your Stripe webhook handler route from CSRF protection since Stripe will not know what CSRF token to send to your routes. - -Typically, you should place these kinds of routes outside of the `web` middleware group that the `RouteServiceProvider` applies to all routes in the `routes/web.php` file. However, you may also exclude the routes by adding their URIs to the `$except` property of the `VerifyCsrfToken` middleware: - - -## X-CSRF-TOKEN - -In addition to checking for the CSRF token as a POST parameter, the `VerifyCsrfToken` middleware will also check for the `X-CSRF-TOKEN` request header. You could, for example, store the token in a HTML `meta` tag: - - - -Then, once you have created the `meta` tag, you can instruct a library like jQuery to automatically add the token to all request headers. This provides simple, convenient CSRF protection for your AJAX based applications: - - $.ajaxSetup({ - headers: { - 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') - } - }); - - -## X-XSRF-TOKEN - -Laravel stores the current CSRF token in a `XSRF-TOKEN` cookie that is included with each response generated by the framework. You can use the cookie value to set the `X-XSRF-TOKEN` request header. - -This cookie is primarily sent as a convenience since some JavaScript frameworks, like Angular, automatically place its value in the `X-XSRF-TOKEN` header. diff --git a/database-testing.md b/database-testing.md deleted file mode 100644 index 27898fa..0000000 --- a/database-testing.md +++ /dev/null @@ -1,226 +0,0 @@ -# Database Testing - -- [Introduction](#introduction) -- [Resetting The Database After Each Test](#resetting-the-database-after-each-test) - - [Using Migrations](#using-migrations) - - [Using Transactions](#using-transactions) -- [Writing Factories](#writing-factories) - - [Factory Types](#factory-types) -- [Using Factories](#using-factories) - - [Creating Models](#creating-models) - - [Persisting Models](#persisting-models) - - [Relationships](#relationships) - - -## Introduction - -Laravel provides a variety of helpful tools to make it easier to test your database driven applications. First, you may use the `seeInDatabase` helper to assert that data exists in the database matching a given set of criteria. For example, if you would like to verify that there is a record in the `users` table with the `email` value of `sally@example.com`, you can do the following: - - public function testDatabase() - { - // Make call to application... - - $this->seeInDatabase('users', [ - 'email' => 'sally@example.com' - ]); - } - -Of course, the `seeInDatabase` method and other helpers like it are for convenience. You are free to use any of PHPUnit's built-in assertion methods to supplement your tests. - - -## Resetting The Database After Each Test - -It is often useful to reset your database after each test so that data from a previous test does not interfere with subsequent tests. - - -### Using Migrations - -One approach to resetting the database state is to rollback the database after each test and migrate it before the next test. Laravel provides a simple `DatabaseMigrations` trait that will automatically handle this for you. Simply use the trait on your test class and everything will be handled for you: - - visit('/') - ->see('Laravel 5'); - } - } - - -### Using Transactions - -Another approach to resetting the database state is to wrap each test case in a database transaction. Again, Laravel provides a convenient `DatabaseTransactions` trait that will automatically handle this for you: - - visit('/') - ->see('Laravel 5'); - } - } - -> {note} This trait will only wrap the default database connection in a transaction. If your application is using multiple database connections, you will need to manually handle the transaction logic for those connections. - - -## Writing Factories - -When testing, it is common to need to insert a few records into your database before executing your test. Instead of manually specifying the value of each column when you create this test data, Laravel allows you to define a default set of attributes for each of your [Eloquent models](/docs/{{version}}/eloquent) using model factories. To get started, take a look at the `database/factories/ModelFactory.php` file in your application. Out of the box, this file contains one factory definition: - - $factory->define(App\User::class, function (Faker\Generator $faker) { - return [ - 'name' => $faker->name, - 'email' => $faker->email, - 'password' => bcrypt(str_random(10)), - 'remember_token' => str_random(10), - ]; - }); - -Within the Closure, which serves as the factory definition, you may return the default test values of all attributes on the model. The Closure will receive an instance of the [Faker](https://github.com/fzaninotto/Faker) PHP library, which allows you to conveniently generate various kinds of random data for testing. - -Of course, you are free to add your own additional factories to the `ModelFactory.php` file. You may also create additional factory files for each model for better organization. For example, you could create `UserFactory.php` and `CommentFactory.php` files within your `database/factories` directory. All of the files within the `factories` directory will automatically be loaded by Laravel. - - -### Factory Types - -Sometimes you may wish to have multiple factories for the same Eloquent model class. For example, perhaps you would like to have a factory for "Administrator" users in addition to normal users. You may define these factories using the `defineAs` method: - - $factory->defineAs(App\User::class, 'admin', function ($faker) { - return [ - 'name' => $faker->name, - 'email' => $faker->email, - 'password' => str_random(10), - 'remember_token' => str_random(10), - 'admin' => true, - ]; - }); - -Instead of duplicating all of the attributes from your base user factory, you may use the `raw` method to retrieve the base attributes. Once you have the attributes, simply supplement them with any additional values you require: - - $factory->defineAs(App\User::class, 'admin', function ($faker) use ($factory) { - $user = $factory->raw(App\User::class); - - return array_merge($user, ['admin' => true]); - }); - - -## Using Factories - - -### Creating Models - -Once you have defined your factories, you may use the global `factory` function in your tests or seed files to generate model instances. So, let's take a look at a few examples of creating models. First, we'll use the `make` method to create models but not save them to the database: - - public function testDatabase() - { - $user = factory(App\User::class)->make(); - - // Use model in tests... - } - -You may also create a Collection of many models or create models of a given type: - - // Create three App\User instances... - $users = factory(App\User::class, 3)->make(); - - // Create an "admin" App\User instance... - $user = factory(App\User::class, 'admin')->make(); - - // Create three "admin" App\User instances... - $users = factory(App\User::class, 'admin', 3)->make(); - -#### Overriding Attributes - -If you would like to override some of the default values of your models, you may pass an array of values to the `make` method. Only the specified values will be replaced while the rest of the values remain set to their default values as specified by the factory: - - $user = factory(App\User::class)->make([ - 'name' => 'Abigail', - ]); - - -### Persisting Models - -The `create` method not only creates the model instances but also saves them to the database using Eloquent's `save` method: - - public function testDatabase() - { - // Create a single App\User instance... - $user = factory(App\User::class)->create(); - - // Create three App\User instances... - $users = factory(App\User::class, 3)->create(); - - // Use model in tests... - } - -You may override attributes on the model by passing an array to the `create` method: - - $user = factory(App\User::class)->create([ - 'name' => 'Abigail', - ]); - - -### Relationships - -In this example, we'll attach a relation to some created models. When using the `create` method to create multiple models, an Eloquent [collection instance](/docs/{{version}}/eloquent-collections) is returned, allowing you to use any of the convenient functions provided by the collection, such as `each`: - - $users = factory(App\User::class, 3) - ->create() - ->each(function ($u) { - $u->posts()->save(factory(App\Post::class)->make()); - }); - -#### Relations & Attribute Closures - -You may also attach relationships to models using Closure attributes in your factory definitions. For example, if you would like to create a new `User` instance when creating a `Post`, you may do the following: - - $factory->define(App\Post::class, function ($faker) { - return [ - 'title' => $faker->title, - 'content' => $faker->paragraph, - 'user_id' => function () { - return factory(App\User::class)->create()->id; - } - ]; - }); - -These Closures also receive the evaluated attribute array of the factory that contains them: - - $factory->define(App\Post::class, function ($faker) { - return [ - 'title' => $faker->title, - 'content' => $faker->paragraph, - 'user_id' => function () { - return factory(App\User::class)->create()->id; - }, - 'user_type' => function (array $post) { - return App\User::find($post['user_id'])->type; - } - ]; - }); diff --git a/database.md b/database.md index ad14737..82805c1 100644 --- a/database.md +++ b/database.md @@ -1,223 +1,134 @@ -# Database: Getting Started - -- [Introduction](#introduction) - - [Configuration](#configuration) - - [Read & Write Connections](#read-and-write-connections) - - [Using Multiple Database Connections](#using-multiple-database-connections) -- [Running Raw SQL Queries](#running-queries) - - [Listening For Query Events](#listening-for-query-events) -- [Database Transactions](#database-transactions) -- [Using Multiple Database Connections](#accessing-connections) - - -## Introduction +# Basic Database Usage -Laravel makes interacting with databases extremely simple across a variety of database backends using either raw SQL, the [fluent query builder](/docs/{{version}}/queries), and the [Eloquent ORM](/docs/{{version}}/eloquent). Currently, Laravel supports four databases: - -
    -- MySQL -- Postgres -- SQLite -- SQL Server -
    +- [Configuration](#configuration) +- [Read / Write Connections](#read-write-connections) +- [Running Queries](#running-queries) +- [Database Transactions](#database-transactions) +- [Accessing Connections](#accessing-connections) +- [Query Logging](#query-logging) -### Configuration - -The database configuration for your application is located at `config/database.php`. In this file you may define all of your database connections, as well as specify which connection should be used by default. Examples for most of the supported database systems are provided in this file. - -By default, Laravel's sample [environment configuration](/docs/{{version}}/installation#environment-configuration) is ready to use with [Laravel Homestead](/docs/{{version}}/homestead), which is a convenient virtual machine for doing Laravel development on your local machine. Of course, you are free to modify this configuration as needed for your local database. - -#### SQLite Configuration - -After creating a new SQLite database using a command such as `touch database/database.sqlite`, you can easily configure your environment variables to point to this newly created database by using the database's absolute path: +## Configuration - DB_CONNECTION=sqlite - DB_DATABASE=/absolute/path/to/database.sqlite +Laravel makes connecting with databases and running queries extremely simple. The database configuration file is `app/config/database.php`. In this file you may define all of your database connections, as well as specify which connection should be used by default. Examples for all of the supported database systems are provided in this file. -#### SQL Server Configuration +Currently Laravel supports four database systems: MySQL, Postgres, SQLite, and SQL Server. -Laravel supports SQL Server out of the box; however, you will need to add the connection configuration for the database to your `config/database.php` configuration file: - - 'sqlsrv' => [ - 'driver' => 'sqlsrv', - 'host' => env('DB_HOST', 'localhost'), - 'database' => env('DB_DATABASE', 'forge'), - 'username' => env('DB_USERNAME', 'forge'), - 'password' => env('DB_PASSWORD', ''), - 'charset' => 'utf8', - 'prefix' => '', - ], - - -### Read & Write Connections + +## Read / Write Connections Sometimes you may wish to use one database connection for SELECT statements, and another for INSERT, UPDATE, and DELETE statements. Laravel makes this a breeze, and the proper connections will always be used whether you are using raw queries, the query builder, or the Eloquent ORM. To see how read / write connections should be configured, let's look at this example: - 'mysql' => [ - 'read' => [ - 'host' => '192.168.1.1', - ], - 'write' => [ - 'host' => '196.168.1.2' - ], - 'driver' => 'mysql', - 'database' => 'database', - 'username' => 'root', - 'password' => '', - 'charset' => 'utf8', - 'collation' => 'utf8_unicode_ci', - 'prefix' => '', - ], - -Note that two keys have been added to the configuration array: `read` and `write`. Both of these keys have array values containing a single key: `host`. The rest of the database options for the `read` and `write` connections will be merged from the main `mysql` array. - -You only need to place items in the `read` and `write` arrays if you wish to override the values from the main array. So, in this case, `192.168.1.1` will be used as the host for the "read" connection, while `192.168.1.2` will be used for the "write" connection. The database credentials, prefix, character set, and all other options in the main `mysql` array will be shared across both connections. + 'mysql' => array( + 'read' => array( + 'host' => '192.168.1.1', + ), + 'write' => array( + 'host' => '196.168.1.2' + ), + 'driver' => 'mysql', + 'database' => 'database', + 'username' => 'root', + 'password' => '', + 'charset' => 'utf8', + 'collation' => 'utf8_unicode_ci', + 'prefix' => '', + ), + +Note that two keys have been added to the configuration array: `read` and `write`. Both of these keys have array values containing a single key: `host`. The rest of the database options for the `read` and `write` connections will be merged from the main `mysql` array. So, we only need to place items in the `read` and `write` arrays if we wish to override the values in the main array. So, in this case, `192.168.1.1` will be used as the "read" connection, while `192.168.1.2` will be used as the "write" connection. The database credentials, prefix, character set, and all other options in the main `mysql` array will be shared across both connections. - -### Using Multiple Database Connections - -When using multiple connections, you may access each connection via the `connection` method on the `DB` facade. The `name` passed to the `connection` method should correspond to one of the connections listed in your `config/database.php` configuration file: + +## Running Queries - $users = DB::connection('foo')->select(...); +Once you have configured your database connection, you may run queries using the `DB` class. -You may also access the raw, underlying PDO instance using the `getPdo` method on a connection instance: +#### Running A Select Query - $pdo = DB::connection()->getPdo(); + $results = DB::select('select * from users where id = ?', array(1)); - -## Running Raw SQL Queries +The `select` method will always return an `array` of results. -Once you have configured your database connection, you may run queries using the `DB` facade. The `DB` facade provides methods for each type of query: `select`, `update`, `insert`, `delete`, and `statement`. +#### Running An Insert Statement -#### Running A Select Query + DB::insert('insert into users (id, name) values (?, ?)', array(1, 'Dayle')); -To run a basic query, you may use the `select` method on the `DB` facade: +#### Running An Update Statement - **Note:** The `update` and `delete` statements return the number of rows affected by the operation. - return view('user.index', ['users' => $users]); - } - } +#### Running A General Statement -The first argument passed to the `select` method is the raw SQL query, while the second argument is any parameter bindings that need to be bound to the query. Typically, these are the values of the `where` clause constraints. Parameter binding provides protection against SQL injection. + DB::statement('drop table users'); -The `select` method will always return an `array` of results. Each result within the array will be a PHP `StdClass` object, allowing you to access the values of the results: +#### Listening For Query Events - foreach ($users as $user) { - echo $user->name; - } +You may listen for query events using the `DB::listen` method: -#### Using Named Bindings + DB::listen(function($sql, $bindings, $time) + { + // + }); -Instead of using `?` to represent your parameter bindings, you may execute a query using named bindings: + +## Database Transactions - $results = DB::select('select * from users where id = :id', ['id' => 1]); +To run a set of operations within a database transaction, you may use the `transaction` method: -#### Running An Insert Statement + DB::transaction(function() + { + DB::table('users')->update(array('votes' => 1)); -To execute an `insert` statement, you may use the `insert` method on the `DB` facade. Like `select`, this method takes the raw SQL query as its first argument and bindings as its second argument: + DB::table('posts')->delete(); + }); - DB::insert('insert into users (id, name) values (?, ?)', [1, 'Dayle']); +> **Note:** Any exception thrown within the `transaction` closure will cause the transaction to be rolled back automatically. -#### Running An Update Statement +Sometimes you may need to begin a transaction yourself: -The `update` method should be used to update existing records in the database. The number of rows affected by the statement will be returned: + DB::beginTransaction(); - $affected = DB::update('update users set votes = 100 where name = ?', ['John']); +You can rollback a transaction via the `rollback` method: -#### Running A Delete Statement + DB::rollback(); -The `delete` method should be used to delete records from the database. Like `update`, the number of rows affected will be returned: +Lastly, you can commit a transaction via the `commit` method: - $deleted = DB::delete('delete from users'); + DB::commit(); -#### Running A General Statement + +## Accessing Connections -Some database statements do not return any value. For these types of operations, you may use the `statement` method on the `DB` facade: - - DB::statement('drop table users'); - - -### Listening For Query Events - -If you would like to receive each SQL query executed by your application, you may use the `listen` method. This method is useful for logging queries or debugging. You may register your query listener in a [service provider](/docs/{{version}}/providers): - - sql - // $query->bindings - // $query->time - }); - } - - /** - * Register the service provider. - * - * @return void - */ - public function register() - { - // - } - } +When using multiple connections, you may access them via the `DB::connection` method: - -## Database Transactions + $users = DB::connection('foo')->select(...); -You may use the `transaction` method on the `DB` facade to run a set of operations within a database transaction. If an exception is thrown within the transaction `Closure`, the transaction will automatically be rolled back. If the `Closure` executes successfully, the transaction will automatically be committed. You don't need to worry about manually rolling back or committing while using the `transaction` method: +You may also access the raw, underlying PDO instance: - DB::transaction(function () { - DB::table('users')->update(['votes' => 1]); + $pdo = DB::connection()->getPdo(); - DB::table('posts')->delete(); - }); +Sometimes you may need to reconnect to a given database: -#### Manually Using Transactions + DB::reconnect('foo'); -If you would like to begin a transaction manually and have complete control over rollbacks and commits, you may use the `beginTransaction` method on the `DB` facade: +If you need to disconnect from the given database due to exceeding the underlying PDO instance's `max_connections` limit, use the `disconnect` method: - DB::beginTransaction(); + DB::disconnect('foo'); -You can rollback the transaction via the `rollBack` method: + +## Query Logging - DB::rollBack(); +By default, Laravel keeps a log in memory of all queries that have been run for the current request. However, in some cases, such as when inserting a large number of rows, this can cause the application to use excess memory. To disable the log, you may use the `disableQueryLog` method: -Lastly, you can commit a transaction via the `commit` method: + DB::connection()->disableQueryLog(); - DB::commit(); +To get an array of the executed queries, you may use the `getQueryLog` method: -> {tip} Using the `DB` facade's transaction methods also controls transactions for the [query builder](/docs/{{version}}/queries) and [Eloquent ORM](/docs/{{version}}/eloquent). + $queries = DB::getQueryLog(); diff --git a/documentation.md b/documentation.md index 328d7ef..fb79572 100644 --- a/documentation.md +++ b/documentation.md @@ -1,78 +1,46 @@ -- Prologue - - [Release Notes](/docs/{{version}}/releases) - - [Upgrade Guide](/docs/{{version}}/upgrade) - - [Contribution Guide](/docs/{{version}}/contributions) - - [API Documentation](/api/{{version}}) +- Preface + - [Introduction](introduction.md) + - [Quickstart](quick.md) + - [Release Notes](releases.md) + - [Upgrade Guide](upgrade.md) - Getting Started - - [Installation](/docs/{{version}}/installation) - - [Configuration](/docs/{{version}}/configuration) - - [Directory Structure](/docs/{{version}}/structure) - - [Errors & Logging](/docs/{{version}}/errors) -- Dev Environments - - [Homestead](/docs/{{version}}/homestead) - - [Valet](/docs/{{version}}/valet) -- Core Concepts - - [Service Container](/docs/{{version}}/container) - - [Service Providers](/docs/{{version}}/providers) - - [Facades](/docs/{{version}}/facades) - - [Contracts](/docs/{{version}}/contracts) -- The HTTP Layer - - [Routing](/docs/{{version}}/routing) - - [Middleware](/docs/{{version}}/middleware) - - [CSRF Protection](/docs/{{version}}/csrf) - - [Controllers](/docs/{{version}}/controllers) - - [Requests](/docs/{{version}}/requests) - - [Responses](/docs/{{version}}/responses) - - [Session](/docs/{{version}}/session) - - [Validation](/docs/{{version}}/validation) -- Frontend - - [Views](/docs/{{version}}/views) - - [Blade Templates](/docs/{{version}}/blade) - - [Compiling Assets](/docs/{{version}}/elixir) - - [Localization](/docs/{{version}}/localization) -- Security - - [Authentication](/docs/{{version}}/authentication) - - [Authorization](/docs/{{version}}/authorization) - - [Password Reset](/docs/{{version}}/passwords) - - [Encryption](/docs/{{version}}/encryption) - - [Hashing](/docs/{{version}}/hashing) -- API Development - - [Authentication](/docs/{{version}}/api-authentication) -- General Topics - - [Broadcasting](/docs/{{version}}/broadcasting) - - [Cache](/docs/{{version}}/cache) - - [Events](/docs/{{version}}/events) - - [File Storage](/docs/{{version}}/filesystem) - - [Mail](/docs/{{version}}/mail) - - [Notifications](/docs/{{version}}/notifications) - - [Queues](/docs/{{version}}/queues) + - [Installation](installation.md) + - [Configuration](configuration.md) + - [Homestead](homestead.md) + - [Request Lifecycle](lifecycle.md) + - [Routing](routing.md) + - [Requests & Input](requests.md) + - [Views & Responses](responses.md) + - [Controllers](controllers.md) + - [Errors & Logging](errors.md) +- Learning More + - [Authentication](security.md) + - [Billing](billing.md) + - [Cache](cache.md) + - [Core Extension](extending.md) + - [Events](events.md) + - [Facades](facades.md) + - [Forms & HTML](html.md) + - [Helpers](helpers.md) + - [IoC Container](ioc.md) + - [Localization](localization.md) + - [Mail](mail.md) + - [Package Development](packages.md) + - [Pagination](pagination.md) + - [Queues](queues.md) + - [Security](security.md) + - [Session](session.md) + - [SSH](ssh.md) + - [Templates](templates.md) + - [Unit Testing](testing.md) + - [Validation](validation.md) - Database - - [Getting Started](/docs/{{version}}/database) - - [Query Builder](/docs/{{version}}/queries) - - [Pagination](/docs/{{version}}/pagination) - - [Migrations](/docs/{{version}}/migrations) - - [Seeding](/docs/{{version}}/seeding) - - [Redis](/docs/{{version}}/redis) -- Eloquent ORM - - [Getting Started](/docs/{{version}}/eloquent) - - [Relationships](/docs/{{version}}/eloquent-relationships) - - [Collections](/docs/{{version}}/eloquent-collections) - - [Mutators](/docs/{{version}}/eloquent-mutators) - - [Serialization](/docs/{{version}}/eloquent-serialization) -- Artisan Console - - [Commands](/docs/{{version}}/artisan) - - [Task Scheduling](/docs/{{version}}/scheduling) -- Testing - - [Getting Started](/docs/{{version}}/testing) - - [Application Testing](/docs/{{version}}/application-testing) - - [Database](/docs/{{version}}/database-testing) - - [Mocking](/docs/{{version}}/mocking) -- Official Packages - - [Cashier](/docs/{{version}}/billing) - - [Envoy](/docs/{{version}}/envoy) - - [Scout](/docs/{{version}}/scout) - - [Socialite](https://github.com/laravel/socialite) -- Appendix - - [Collections](/docs/{{version}}/collections) - - [Helpers](/docs/{{version}}/helpers) - - [Packages](/docs/{{version}}/packages) + - [Basic Usage](database.md) + - [Query Builder](queries.md) + - [Eloquent ORM](eloquent.md) + - [Schema Builder](schema.md) + - [Migrations & Seeding](migrations.md) + - [Redis](redis.md) +- Artisan CLI + - [Overview](artisan.md) + - [Development](commands.md) \ No newline at end of file diff --git a/elixir.md b/elixir.md deleted file mode 100644 index cb80437..0000000 --- a/elixir.md +++ /dev/null @@ -1,351 +0,0 @@ -# Compiling Assets (Laravel Elixir) - -- [Introduction](#introduction) -- [Installation & Setup](#installation) -- [Running Elixir](#running-elixir) -- [Working With Stylesheets](#working-with-stylesheets) - - [Less](#less) - - [Sass](#sass) - - [Stylus](#stylus) - - [Plain CSS](#plain-css) - - [Source Maps](#css-source-maps) -- [Working With Scripts](#working-with-scripts) - - [Webpack](#webpack) - - [Rollup](#rollup) - - [Scripts](#javascript) -- [Copying Files & Directories](#copying-files-and-directories) -- [Versioning / Cache Busting](#versioning-and-cache-busting) -- [BrowserSync](#browser-sync) - - -## Introduction - -Laravel Elixir provides a clean, fluent API for defining basic [Gulp](http://gulpjs.com) tasks for your Laravel application. Elixir supports common CSS and JavaScript pre-processors like [Sass](http://sass-lang.com) and [Webpack](https://webpack.github.io/). Using method chaining, Elixir allows you to fluently define your asset pipeline. For example: - -```javascript -elixir(function(mix) { - mix.sass('app.scss') - .webpack('app.js'); -}); -``` - -If you've ever been confused and overwhelmed about getting started with Gulp and asset compilation, you will love Laravel Elixir. However, you are not required to use it while developing your application. You are free to use any asset pipeline tool you wish, or even none at all. - - -## Installation & Setup - -#### Installing Node - -Before triggering Elixir, you must first ensure that Node.js and NPM are installed on your machine. - - node -v - npm -v - -By default, Laravel Homestead includes everything you need; however, if you aren't using Vagrant, then you can easily install the latest version of Node and NPM using simple graphical installers from [their download page](http://nodejs.org/en/download/). - -#### Gulp - -Next, you'll need to pull in [Gulp](http://gulpjs.com) as a global NPM package: - - npm install --global gulp-cli - -#### Laravel Elixir - -The only remaining step is to install Laravel Elixir. Within a fresh installation of Laravel, you'll find a `package.json` file in the root of your directory structure. The default `package.json` file includes Elixir and the Webpack JavaScript module bundler. Think of this like your `composer.json` file, except it defines Node dependencies instead of PHP. You may install the dependencies it references by running: - - npm install - -If you are developing on a Windows system or you are running your VM on a Windows host system, you may need to run the `npm install` command with the `--no-bin-links` switch enabled: - - npm install --no-bin-links - - -## Running Elixir - -Elixir is built on top of [Gulp](http://gulpjs.com), so to run your Elixir tasks you only need to run the `gulp` command in your terminal. Adding the `--production` flag to the command will instruct Elixir to minify your CSS and JavaScript files: - - // Run all tasks... - gulp - - // Run all tasks and minify all CSS and JavaScript... - gulp --production - -Upon running this command, you'll see a nicely formatted table that displays a summary of the events that just took place. - -#### Watching Assets For Changes - -The `gulp watch` command will continue running in your terminal and watch your assets for any changes. Gulp will automatically recompile your assets if you modify them while the `watch` command is running: - - gulp watch - - -## Working With Stylesheets - -The `gulpfile.js` file in your project's root directory contains all of your Elixir tasks. Elixir tasks can be chained together to define exactly how your assets should be compiled. - - -### Less - -The `less` method may be used to compile [Less](http://lesscss.org/) into CSS. The `less` method assumes that your Less files are stored in `resources/assets/less`. By default, the task will place the compiled CSS for this example in `public/css/app.css`: - -```javascript -elixir(function(mix) { - mix.less('app.less'); -}); -``` - -You may also combine multiple Less files into a single CSS file. Again, the resulting CSS will be placed in `public/css/app.css`: - -```javascript -elixir(function(mix) { - mix.less([ - 'app.less', - 'controllers.less' - ]); -}); -``` - -If you wish to customize the output location of the compiled CSS, you may pass a second argument to the `less` method: - -```javascript -elixir(function(mix) { - mix.less('app.less', 'public/stylesheets'); -}); - -// Specifying a specific output filename... -elixir(function(mix) { - mix.less('app.less', 'public/stylesheets/style.css'); -}); -``` - - -### Sass - -The `sass` method allows you to compile [Sass](http://sass-lang.com/) into CSS. Assuming your Sass files are stored at `resources/assets/sass`, you may use the method like so: - -```javascript -elixir(function(mix) { - mix.sass('app.scss'); -}); -``` - -Again, like the `less` method, you may compile multiple Sass files into a single CSS file, and even customize the output directory of the resulting CSS: - -```javascript -elixir(function(mix) { - mix.sass([ - 'app.scss', - 'controllers.scss' - ], 'public/assets/css'); -}); -``` - -#### Custom Paths - -While it's recommended that you use Laravel's default asset directories, if you require a different base directory, you may begin any file path with `./`. This instructs Elixir to begin at the project root, rather than using the default base directory. - -For example, to compile a file located at `app/assets/sass/app.scss` and output the results to `public/css/app.css`, you would make the following call to the `sass` method: - -```javascript -elixir(function(mix) { - mix.sass('./app/assets/sass/app.scss'); -}); -``` - - -### Stylus - -The `stylus` method may be used to compile [Stylus](http://stylus-lang.com/) into CSS. Assuming that your Stylus files are stored in `resources/assets/stylus`, you may call the method like so: - -```javascript -elixir(function(mix) { - mix.stylus('app.styl'); -}); -``` - -> {tip} This method's signature is identical to both `mix.less()` and `mix.sass()`. - - -### Plain CSS - -If you would just like to combine some plain CSS stylesheets into a single file, you may use the `styles` method. Paths passed to this method are relative to the `resources/assets/css` directory and the resulting CSS will be placed in `public/css/all.css`: - -```javascript -elixir(function(mix) { - mix.styles([ - 'normalize.css', - 'main.css' - ]); -}); -``` - -You may also instruct Elixir to write the resulting file to a custom directory or file by passing a second argument to the `styles` method: - -```javascript -elixir(function(mix) { - mix.styles([ - 'normalize.css', - 'main.css' - ], 'public/assets/css/site.css'); -}); -``` - - -### Source Maps - -In Elixir, source maps are enabled by default and provide better debugging information to your browser's developer tools when using compiled assets. For each relevant file that is compiled, you will find a companion `*.css.map` or `*.js.map` file in the same directory. - -If you do not want source maps generated for your application, you may disable them using the `sourcemaps` configuration option: - -```javascript -elixir.config.sourcemaps = false; - -elixir(function(mix) { - mix.sass('app.scss'); -}); -``` - - -## Working With Scripts - -Elixir provides several features to help you work with your JavaScript files, such as compiling ECMAScript 2015, module bundling, minification, and simply concatenating plain JavaScript files. - -When writing ES2015 with modules, you have your choice between [Webpack](http://webpack.github.io) and [Rollup](http://rollupjs.org/). If these tools are foreign to you, don't worry, Elixir will handle all of the hard work behind the scenes. By default, the Laravel `gulpfile` uses `webpack` to compile Javascript, but you are free to use any module bundler you like. - - -### Webpack - -The `webpack` method may be used to compile and bundle [ECMAScript 2015](https://babeljs.io/docs/learn-es2015/) into plain JavaScript. This function accepts a file path relative to the `resources/assets/js` directory and generates a single bundled file in the `public/js` directory: - -```javascript -elixir(function(mix) { - mix.webpack('app.js'); -}); -``` - -To choose a different output or base directory, simply specify your desired paths with a leading `.`. Then you may specify the paths relative to the root of your application. For example, to compile `app/assets/js/app.js` to `public/dist/app.js`: - -```javascript -elixir(function(mix) { - mix.webpack( - './resources/assets/js/app.js', - './public/dist' - ); -}); -``` - -If you'd like to leverage more of Webpack's functionality, Elixir will read any `webpack.config.js` file that is in your project root and [factor its configuration](https://webpack.github.io/docs/configuration.html) into the build process. - - - -### Rollup - -Similar to Webpack, Rollup is a next-generation bundler for ES2015. This function accepts an array of files relative to the `resources/assets/js` directory, and generates a single file in the `public/js` directory: - -```javascript -elixir(function(mix) { - mix.rollup('app.js'); -}); -``` - -Like the `webpack` method, you may customize the location of the input and output files given to the `rollup` method: - - elixir(function(mix) { - mix.rollup( - './resources/assets/js/app.js', - './public/dist' - ); - }); - - -### Scripts - -If you have multiple JavaScript files that you would like to combine into a single file, you may use the `scripts` method, which provides automatic source maps, concatenation, and minification. - -The `scripts` method assumes all paths are relative to the `resources/assets/js` directory, and will place the resulting JavaScript in `public/js/all.js` by default: - -```javascript -elixir(function(mix) { - mix.scripts([ - 'order.js', - 'forum.js' - ]); -}); -``` - -If you need to concatenate multiple sets of scripts into different files, you may make multiple calls to the `scripts` method. The second argument given to the method determines the resulting file name for each concatenation: - -```javascript -elixir(function(mix) { - mix.scripts(['app.js', 'controllers.js'], 'public/js/app.js') - .scripts(['forum.js', 'threads.js'], 'public/js/forum.js'); -}); -``` - -If you need to combine all of the scripts in a given directory, you may use the `scriptsIn` method. The resulting JavaScript will be placed in `public/js/all.js`: - -```javascript -elixir(function(mix) { - mix.scriptsIn('public/js/some/directory'); -}); -``` - -> {tip} If you intend to concatenate multiple pre-minified vendor libraries, such as jQuery, instead consider using `mix.combine()`. This will combine the files, while omitting the source map and minification steps. As a result, compile times will drastically improve. - - - -## Copying Files & Directories - -The `copy` method may be used to copy files and directories to new locations. All operations are relative to the project's root directory: - -```javascript -elixir(function(mix) { - mix.copy('vendor/foo/bar.css', 'public/css/bar.css'); -}); -``` - - -## Versioning / Cache Busting - -Many developers suffix their compiled assets with a timestamp or unique token to force browsers to load the fresh assets instead of serving stale copies of the code. Elixir can handle this for you using the `version` method. - -The `version` method accepts a file name relative to the `public` directory, and will append a unique hash to the filename, allowing for cache-busting. For example, the generated file name will look something like: `all-16d570a7.css`: - -```javascript -elixir(function(mix) { - mix.version('css/all.css'); -}); -``` - -After generating the versioned file, you may use Laravel's global `elixir` helper within your [views](/docs/{{version}}/views) to load the appropriately hashed asset. The `elixir` function will automatically determine the current name of the hashed file: - - - -#### Versioning Multiple Files - -You may pass an array to the `version` method to version multiple files: - -```javascript -elixir(function(mix) { - mix.version(['css/all.css', 'js/app.js']); -}); -``` - -Once the files have been versioned, you may use the `elixir` helper function to generate links to the proper hashed files. Remember, you only need to pass the name of the un-hashed file to the `elixir` helper function. The helper will use the un-hashed name to determine the current hashed version of the file: - - - - - - -## BrowserSync - -BrowserSync automatically refreshes your web browser after you make changes to your assets. The `browserSync` method accepts a JavaScript object with a `proxy` attribute containing the local URL for your application. Then, once you run `gulp watch` you may access your web application using port 3000 (`http://project.dev:3000`) to enjoy browser syncing: - -```javascript -elixir(function(mix) { - mix.browserSync({ - proxy: 'project.dev' - }); -}); -``` diff --git a/eloquent-collections.md b/eloquent-collections.md deleted file mode 100644 index 663e90d..0000000 --- a/eloquent-collections.md +++ /dev/null @@ -1,146 +0,0 @@ -# Eloquent: Collections - -- [Introduction](#introduction) -- [Available Methods](#available-methods) -- [Custom Collections](#custom-collections) - - -## Introduction - -All multi-result sets returned by Eloquent are instances of the `Illuminate\Database\Eloquent\Collection` object, including results retrieved via the `get` method or accessed via a relationship. The Eloquent collection object extends the Laravel [base collection](/docs/{{version}}/collections), so it naturally inherits dozens of methods used to fluently work with the underlying array of Eloquent models. - -Of course, all collections also serve as iterators, allowing you to loop over them as if they were simple PHP arrays: - - $users = App\User::where('active', 1)->get(); - - foreach ($users as $user) { - echo $user->name; - } - -However, collections are much more powerful than arrays and expose a variety of map / reduce operations that may be chained using an intuitive interface. For example, let's remove all inactive models and gather the first name for each remaining user: - - $users = App\User::where('active', 1)->get(); - - $names = $users->reject(function ($user) { - return $user->active === false; - }) - ->map(function ($user) { - return $user->name; - }); - -> {note} While most Eloquent collection methods return a new instance of an Eloquent collection, the `pluck`, `keys`, `zip`, `collapse`, `flatten` and `flip` methods return a [base collection](/docs/{{version}}/collections) instance. Likewise, if a `map` operation returns a collection that does not contain any Eloquent models, it will be automatically cast to a base collection. - - -## Available Methods - -### The Base Collection - -All Eloquent collections extend the base [Laravel collection](/docs/{{version}}/collections) object; therefore, they inherit all of the powerful methods provided by the base collection class: - - - -
    - -[all](/docs/{{version}}/collections#method-all) -[avg](/docs/{{version}}/collections#method-avg) -[chunk](/docs/{{version}}/collections#method-chunk) -[collapse](/docs/{{version}}/collections#method-collapse) -[combine](/docs/{{version}}/collections#method-combine) -[contains](/docs/{{version}}/collections#method-contains) -[count](/docs/{{version}}/collections#method-count) -[diff](/docs/{{version}}/collections#method-diff) -[diffKeys](/docs/{{version}}/collections#method-diffkeys) -[each](/docs/{{version}}/collections#method-each) -[every](/docs/{{version}}/collections#method-every) -[except](/docs/{{version}}/collections#method-except) -[filter](/docs/{{version}}/collections#method-filter) -[first](/docs/{{version}}/collections#method-first) -[flatMap](/docs/{{version}}/collections#method-flatmap) -[flatten](/docs/{{version}}/collections#method-flatten) -[flip](/docs/{{version}}/collections#method-flip) -[forget](/docs/{{version}}/collections#method-forget) -[forPage](/docs/{{version}}/collections#method-forpage) -[get](/docs/{{version}}/collections#method-get) -[groupBy](/docs/{{version}}/collections#method-groupby) -[has](/docs/{{version}}/collections#method-has) -[implode](/docs/{{version}}/collections#method-implode) -[intersect](/docs/{{version}}/collections#method-intersect) -[isEmpty](/docs/{{version}}/collections#method-isempty) -[keyBy](/docs/{{version}}/collections#method-keyby) -[keys](/docs/{{version}}/collections#method-keys) -[last](/docs/{{version}}/collections#method-last) -[map](/docs/{{version}}/collections#method-map) -[max](/docs/{{version}}/collections#method-max) -[merge](/docs/{{version}}/collections#method-merge) -[min](/docs/{{version}}/collections#method-min) -[only](/docs/{{version}}/collections#method-only) -[pluck](/docs/{{version}}/collections#method-pluck) -[pop](/docs/{{version}}/collections#method-pop) -[prepend](/docs/{{version}}/collections#method-prepend) -[pull](/docs/{{version}}/collections#method-pull) -[push](/docs/{{version}}/collections#method-push) -[put](/docs/{{version}}/collections#method-put) -[random](/docs/{{version}}/collections#method-random) -[reduce](/docs/{{version}}/collections#method-reduce) -[reject](/docs/{{version}}/collections#method-reject) -[reverse](/docs/{{version}}/collections#method-reverse) -[search](/docs/{{version}}/collections#method-search) -[shift](/docs/{{version}}/collections#method-shift) -[shuffle](/docs/{{version}}/collections#method-shuffle) -[slice](/docs/{{version}}/collections#method-slice) -[sort](/docs/{{version}}/collections#method-sort) -[sortBy](/docs/{{version}}/collections#method-sortby) -[sortByDesc](/docs/{{version}}/collections#method-sortbydesc) -[splice](/docs/{{version}}/collections#method-splice) -[sum](/docs/{{version}}/collections#method-sum) -[take](/docs/{{version}}/collections#method-take) -[toArray](/docs/{{version}}/collections#method-toarray) -[toJson](/docs/{{version}}/collections#method-tojson) -[transform](/docs/{{version}}/collections#method-transform) -[union](/docs/{{version}}/collections#method-union) -[unique](/docs/{{version}}/collections#method-unique) -[values](/docs/{{version}}/collections#method-values) -[where](/docs/{{version}}/collections#method-where) -[whereStrict](/docs/{{version}}/collections#method-wherestrict) -[whereIn](/docs/{{version}}/collections#method-wherein) -[whereInLoose](/docs/{{version}}/collections#method-whereinloose) -[zip](/docs/{{version}}/collections#method-zip) - -
    - - -## Custom Collections - -If you need to use a custom `Collection` object with your own extension methods, you may override the `newCollection` method on your model: - - -## Introduction - -Accessors and mutators allow you to format Eloquent attribute values when you retrieve or set them on model instances. For example, you may want to use the [Laravel encrypter](/docs/{{version}}/encryption) to encrypt a value while it is stored in the database, and then automatically decrypt the attribute when you access it on an Eloquent model. - -In addition to custom accessors and mutators, Eloquent can also automatically cast date fields to [Carbon](https://github.com/briannesbitt/Carbon) instances or even [cast text fields to JSON](#attribute-casting). - - -## Accessors & Mutators - - -### Defining An Accessor - -To define an accessor, create a `getFooAttribute` method on your model where `Foo` is the "studly" cased name of the column you wish to access. In this example, we'll define an accessor for the `first_name` attribute. The accessor will automatically be called by Eloquent when attempting to retrieve the value of the `first_name` attribute: - - first_name; - - -### Defining A Mutator - -To define a mutator, define a `setFooAttribute` method on your model where `Foo` is the "studly" cased name of the column you wish to access. So, again, let's define a mutator for the `first_name` attribute. This mutator will be automatically called when we attempt to set the value of the `first_name` attribute on the model: - - attributes['first_name'] = strtolower($value); - } - } - -The mutator will receive the value that is being set on the attribute, allowing you to manipulate the value and set the manipulated value on the Eloquent model's internal `$attributes` property. So, for example, if we attempt to set the `first_name` attribute to `Sally`: - - $user = App\User::find(1); - - $user->first_name = 'Sally'; - -In this example, the `setFirstNameAttribute` function will be called with the value `Sally`. The mutator will then apply the `strtolower` function to the name and set its resulting value in the internal `$attributes` array. - - -## Date Mutators - -By default, Eloquent will convert the `created_at` and `updated_at` columns to instances of [Carbon](https://github.com/briannesbitt/Carbon), which extends the PHP `DateTime` class to provide an assortment of helpful methods. You may customize which dates are automatically mutated, and even completely disable this mutation, by overriding the `$dates` property of your model: - - deleted_at = Carbon::now(); - - $user->save(); - -As noted above, when retrieving attributes that are listed in your `$dates` property, they will automatically be cast to [Carbon](https://github.com/briannesbitt/Carbon) instances, allowing you to use any of Carbon's methods on your attributes: - - $user = App\User::find(1); - - return $user->deleted_at->getTimestamp(); - -#### Date Formats - -By default, timestamps are formatted as `'Y-m-d H:i:s'`. If you need to customize the timestamp format, set the `$dateFormat` property on your model. This property determines how date attributes are stored in the database, as well as their format when the model is serialized to an array or JSON: - - -## Attribute Casting - -The `$casts` property on your model provides a convenient method of converting attributes to common data types. The `$casts` property should be an array where the key is the name of the attribute being cast and the value is the type you wish to cast the column to. The supported cast types are: `integer`, `real`, `float`, `double`, `string`, `boolean`, `object`, `array`, `collection`, `date`, `datetime`, and `timestamp`. - -For example, let's cast the `is_admin` attribute, which is stored in our database as an integer (`0` or `1`) to a boolean value: - - 'boolean', - ]; - } - -Now the `is_admin` attribute will always be cast to a boolean when you access it, even if the underlying value is stored in the database as an integer: - - $user = App\User::find(1); - - if ($user->is_admin) { - // - } - - -### Array & JSON Casting - -The `array` cast type is particularly useful when working with columns that are stored as serialized JSON. For example, if your database has a `JSON` or `TEXT` field type that contains serialized JSON, adding the `array` cast to that attribute will automatically deserialize the attribute to a PHP array when you access it on your Eloquent model: - - 'array', - ]; - } - -Once the cast is defined, you may access the `options` attribute and it will automatically be deserialized from JSON into a PHP array. When you set the value of the `options` attribute, the given array will automatically be serialized back into JSON for storage: - - $user = App\User::find(1); - - $options = $user->options; - - $options['key'] = 'value'; - - $user->options = $options; - - $user->save(); diff --git a/eloquent-relationships.md b/eloquent-relationships.md deleted file mode 100644 index fa31cce..0000000 --- a/eloquent-relationships.md +++ /dev/null @@ -1,882 +0,0 @@ -# Eloquent: Relationships - -- [Introduction](#introduction) -- [Defining Relationships](#defining-relationships) - - [One To One](#one-to-one) - - [One To Many](#one-to-many) - - [One To Many (Inverse)](#one-to-many-inverse) - - [Many To Many](#many-to-many) - - [Has Many Through](#has-many-through) - - [Polymorphic Relations](#polymorphic-relations) - - [Many To Many Polymorphic Relations](#many-to-many-polymorphic-relations) -- [Querying Relations](#querying-relations) - - [Relationship Methods Vs. Dynamic Properties](#relationship-methods-vs-dynamic-properties) - - [Querying Relationship Existence](#querying-relationship-existence) - - [Counting Related Models](#counting-related-models) -- [Eager Loading](#eager-loading) - - [Constraining Eager Loads](#constraining-eager-loads) - - [Lazy Eager Loading](#lazy-eager-loading) -- [Inserting & Updating Related Models](#inserting-and-updating-related-models) - - [The `save` Method](#the-save-method) - - [The `create` Method](#the-create-method) - - [Belongs To Relationships](#updating-belongs-to-relationships) - - [Many To Many Relationships](#updating-many-to-many-relationships) -- [Touching Parent Timestamps](#touching-parent-timestamps) - - -## Introduction - -Database tables are often related to one another. For example, a blog post may have many comments, or an order could be related to the user who placed it. Eloquent makes managing and working with these relationships easy, and supports several different types of relationships: - -- [One To One](#one-to-one) -- [One To Many](#one-to-many) -- [Many To Many](#many-to-many) -- [Has Many Through](#has-many-through) -- [Polymorphic Relations](#polymorphic-relations) -- [Many To Many Polymorphic Relations](#many-to-many-polymorphic-relations) - - -## Defining Relationships - -Eloquent relationships are defined as functions on your Eloquent model classes. Since, like Eloquent models themselves, relationships also serve as powerful [query builders](/docs/{{version}}/queries), defining relationships as functions provides powerful method chaining and querying capabilities. For example, we may chain additional constraints on this `posts` relationship: - - $user->posts()->where('active', 1)->get(); - -But, before diving too deep into using relationships, let's learn how to define each type. - - -### One To One - -A one-to-one relationship is a very basic relation. For example, a `User` model might be associated with one `Phone`. To define this relationship, we place a `phone` method on the `User` model. The `phone` method should call the `hasOne` method and return its result: - - hasOne('App\Phone'); - } - } - -The first argument passed to the `hasOne` method is the name of the related model. Once the relationship is defined, we may retrieve the related record using Eloquent's dynamic properties. Dynamic properties allow you to access relationship functions as if they were properties defined on the model: - - $phone = User::find(1)->phone; - -Eloquent determines the foreign key of the relationship based on the model name. In this case, the `Phone` model is automatically assumed to have a `user_id` foreign key. If you wish to override this convention, you may pass a second argument to the `hasOne` method: - - return $this->hasOne('App\Phone', 'foreign_key'); - -Additionally, Eloquent assumes that the foreign key should have a value matching the `id` (or the custom `$primaryKey`) column of the parent. In other words, Eloquent will look for the value of the user's `id` column in the `user_id` column of the `Phone` record. If you would like the relationship to use a value other than `id`, you may pass a third argument to the `hasOne` method specifying your custom key: - - return $this->hasOne('App\Phone', 'foreign_key', 'local_key'); - -#### Defining The Inverse Of The Relationship - -So, we can access the `Phone` model from our `User`. Now, let's define a relationship on the `Phone` model that will let us access the `User` that owns the phone. We can define the inverse of a `hasOne` relationship using the `belongsTo` method: - - belongsTo('App\User'); - } - } - -In the example above, Eloquent will try to match the `user_id` from the `Phone` model to an `id` on the `User` model. Eloquent determines the default foreign key name by examining the name of the relationship method and suffixing the method name with `_id`. However, if the foreign key on the `Phone` model is not `user_id`, you may pass a custom key name as the second argument to the `belongsTo` method: - - /** - * Get the user that owns the phone. - */ - public function user() - { - return $this->belongsTo('App\User', 'foreign_key'); - } - -If your parent model does not use `id` as its primary key, or you wish to join the child model to a different column, you may pass a third argument to the `belongsTo` method specifying your parent table's custom key: - - /** - * Get the user that owns the phone. - */ - public function user() - { - return $this->belongsTo('App\User', 'foreign_key', 'other_key'); - } - - -### One To Many - -A "one-to-many" relationship is used to define relationships where a single model owns any amount of other models. For example, a blog post may have an infinite number of comments. Like all other Eloquent relationships, one-to-many relationships are defined by placing a function on your Eloquent model: - - hasMany('App\Comment'); - } - } - -Remember, Eloquent will automatically determine the proper foreign key column on the `Comment` model. By convention, Eloquent will take the "snake case" name of the owning model and suffix it with `_id`. So, for this example, Eloquent will assume the foreign key on the `Comment` model is `post_id`. - -Once the relationship has been defined, we can access the collection of comments by accessing the `comments` property. Remember, since Eloquent provides "dynamic properties", we can access relationship functions as if they were defined as properties on the model: - - $comments = App\Post::find(1)->comments; - - foreach ($comments as $comment) { - // - } - -Of course, since all relationships also serve as query builders, you can add further constraints to which comments are retrieved by calling the `comments` method and continuing to chain conditions onto the query: - - $comments = App\Post::find(1)->comments()->where('title', 'foo')->first(); - -Like the `hasOne` method, you may also override the foreign and local keys by passing additional arguments to the `hasMany` method: - - return $this->hasMany('App\Comment', 'foreign_key'); - - return $this->hasMany('App\Comment', 'foreign_key', 'local_key'); - - -### One To Many (Inverse) - -Now that we can access all of a post's comments, let's define a relationship to allow a comment to access its parent post. To define the inverse of a `hasMany` relationship, define a relationship function on the child model which calls the `belongsTo` method: - - belongsTo('App\Post'); - } - } - -Once the relationship has been defined, we can retrieve the `Post` model for a `Comment` by accessing the `post` "dynamic property": - - $comment = App\Comment::find(1); - - echo $comment->post->title; - -In the example above, Eloquent will try to match the `post_id` from the `Comment` model to an `id` on the `Post` model. Eloquent determines the default foreign key name by examining the name of the relationship method and suffixing the method name with `_id`. However, if the foreign key on the `Comment` model is not `post_id`, you may pass a custom key name as the second argument to the `belongsTo` method: - - /** - * Get the post that owns the comment. - */ - public function post() - { - return $this->belongsTo('App\Post', 'foreign_key'); - } - -If your parent model does not use `id` as its primary key, or you wish to join the child model to a different column, you may pass a third argument to the `belongsTo` method specifying your parent table's custom key: - - /** - * Get the post that owns the comment. - */ - public function post() - { - return $this->belongsTo('App\Post', 'foreign_key', 'other_key'); - } - - -### Many To Many - -Many-to-many relations are slightly more complicated than `hasOne` and `hasMany` relationships. An example of such a relationship is a user with many roles, where the roles are also shared by other users. For example, many users may have the role of "Admin". To define this relationship, three database tables are needed: `users`, `roles`, and `role_user`. The `role_user` table is derived from the alphabetical order of the related model names, and contains the `user_id` and `role_id` columns. - -Many-to-many relationships are defined by writing a method that returns the result of the `belongsToMany` method. For example, let's define the `roles` method on our `User` model: - - belongsToMany('App\Role'); - } - } - -Once the relationship is defined, you may access the user's roles using the `roles` dynamic property: - - $user = App\User::find(1); - - foreach ($user->roles as $role) { - // - } - -Of course, like all other relationship types, you may call the `roles` method to continue chaining query constraints onto the relationship: - - $roles = App\User::find(1)->roles()->orderBy('name')->get(); - -As mentioned previously, to determine the table name of the relationship's joining table, Eloquent will join the two related model names in alphabetical order. However, you are free to override this convention. You may do so by passing a second argument to the `belongsToMany` method: - - return $this->belongsToMany('App\Role', 'role_user'); - -In addition to customizing the name of the joining table, you may also customize the column names of the keys on the table by passing additional arguments to the `belongsToMany` method. The third argument is the foreign key name of the model on which you are defining the relationship, while the fourth argument is the foreign key name of the model that you are joining to: - - return $this->belongsToMany('App\Role', 'role_user', 'user_id', 'role_id'); - -#### Defining The Inverse Of The Relationship - -To define the inverse of a many-to-many relationship, you simply place another call to `belongsToMany` on your related model. To continue our user roles example, let's define the `users` method on the `Role` model: - - belongsToMany('App\User'); - } - } - -As you can see, the relationship is defined exactly the same as its `User` counterpart, with the exception of simply referencing the `App\User` model. Since we're reusing the `belongsToMany` method, all of the usual table and key customization options are available when defining the inverse of many-to-many relationships. - -#### Retrieving Intermediate Table Columns - -As you have already learned, working with many-to-many relations requires the presence of an intermediate table. Eloquent provides some very helpful ways of interacting with this table. For example, let's assume our `User` object has many `Role` objects that it is related to. After accessing this relationship, we may access the intermediate table using the `pivot` attribute on the models: - - $user = App\User::find(1); - - foreach ($user->roles as $role) { - echo $role->pivot->created_at; - } - -Notice that each `Role` model we retrieve is automatically assigned a `pivot` attribute. This attribute contains a model representing the intermediate table, and may be used like any other Eloquent model. - -By default, only the model keys will be present on the `pivot` object. If your pivot table contains extra attributes, you must specify them when defining the relationship: - - return $this->belongsToMany('App\Role')->withPivot('column1', 'column2'); - -If you want your pivot table to have automatically maintained `created_at` and `updated_at` timestamps, use the `withTimestamps` method on the relationship definition: - - return $this->belongsToMany('App\Role')->withTimestamps(); - -#### Filtering Relationships Via Intermediate Table Columns - -You can also filter the results returned by `belongsToMany` using the `wherePivot` and `wherePivotIn` methods when defining the relationship: - - return $this->belongsToMany('App\Role')->wherePivot('approved', 1); - - return $this->belongsToMany('App\Role')->wherePivotIn('priority', [1, 2]); - - -### Has Many Through - -The "has-many-through" relationship provides a convenient short-cut for accessing distant relations via an intermediate relation. For example, a `Country` model might have many `Post` models through an intermediate `User` model. In this example, you could easily gather all blog posts for a given country. Let's look at the tables required to define this relationship: - - countries - id - integer - name - string - - users - id - integer - country_id - integer - name - string - - posts - id - integer - user_id - integer - title - string - -Though `posts` does not contain a `country_id` column, the `hasManyThrough` relation provides access to a country's posts via `$country->posts`. To perform this query, Eloquent inspects the `country_id` on the intermediate `users` table. After finding the matching user IDs, they are used to query the `posts` table. - -Now that we have examined the table structure for the relationship, let's define it on the `Country` model: - - hasManyThrough('App\Post', 'App\User'); - } - } - -The first argument passed to the `hasManyThrough` method is the name of the final model we wish to access, while the second argument is the name of the intermediate model. - -Typical Eloquent foreign key conventions will be used when performing the relationship's queries. If you would like to customize the keys of the relationship, you may pass them as the third and fourth arguments to the `hasManyThrough` method. The third argument is the name of the foreign key on the intermediate model, the fourth argument is the name of the foreign key on the final model, and the fifth argument is the local key: - - class Country extends Model - { - public function posts() - { - return $this->hasManyThrough( - 'App\Post', 'App\User', - 'country_id', 'user_id', 'id' - ); - } - } - - -### Polymorphic Relations - -#### Table Structure - -Polymorphic relations allow a model to belong to more than one other model on a single association. For example, imagine users of your application can "comment" both posts and videos. Using polymorphic relationships, you can use a single `comments` table for both of these scenarios. First, let's examine the table structure required to build this relationship: - - posts - id - integer - title - string - body - text - - videos - id - integer - title - string - url - string - - comments - id - integer - body - text - commentable_id - integer - commentable_type - string - -Two important columns to note are the `commentable_id` and `commentable_type` columns on the `comments` table. The `commentable_id` column will contain the ID value of the post or video, while the `commentable_type` column will contain the class name of the owning model. The `commentable_type` column is how the ORM determines which "type" of owning model to return when accessing the `commentable` relation. - -#### Model Structure - -Next, let's examine the model definitions needed to build this relationship: - - morphTo(); - } - } - - class Post extends Model - { - /** - * Get all of the post's comments. - */ - public function comments() - { - return $this->morphMany('App\Comment', 'commentable'); - } - } - - class Video extends Model - { - /** - * Get all of the video's comments. - */ - public function comments() - { - return $this->morphMany('App\Comment', 'commentable'); - } - } - -#### Retrieving Polymorphic Relations - -Once your database table and models are defined, you may access the relationships via your models. For example, to access all of the comments for a post, we can simply use the `comments` dynamic property: - - $post = App\Post::find(1); - - foreach ($post->comments as $comment) { - // - } - -You may also retrieve the owner of a polymorphic relation from the polymorphic model by accessing the name of the method that performs the call to `morphTo`. In our case, that is the `commentable` method on the `Comment` model. So, we will access that method as a dynamic property: - - $comment = App\Comment::find(1); - - $commentable = $comment->commentable; - -The `commentable` relation on the `Comment` model will return either a `Post` or `Video` instance, depending on which type of model owns the comment. - -#### Custom Polymorphic Types - -By default, Laravel will use the fully qualified class name to store the type of the related model. For instance, given the example above where a `Comment` may belong to a `Post` or a `Video`, the default `commentable_type` would be either `App\Post` or `App\Video`, respectively. However, you may wish to decouple your database from your application's internal structure. In that case, you may define a relationship "morph map" to instruct Eloquent to use a custom name for each model instead of the class name: - - use Illuminate\Database\Eloquent\Relations\Relation; - - Relation::morphMap([ - 'posts' => App\Post::class, - 'videos' => App\Video::class, - ]); - -You may register the `morphMap` in the `boot` function of your `AppServiceProvider` or create a separate service provider if you wish. - - -### Many To Many Polymorphic Relations - -#### Table Structure - -In addition to traditional polymorphic relations, you may also define "many-to-many" polymorphic relations. For example, a blog `Post` and `Video` model could share a polymorphic relation to a `Tag` model. Using a many-to-many polymorphic relation allows you to have a single list of unique tags that are shared across blog posts and videos. First, let's examine the table structure: - - posts - id - integer - name - string - - videos - id - integer - name - string - - tags - id - integer - name - string - - taggables - tag_id - integer - taggable_id - integer - taggable_type - string - -#### Model Structure - -Next, we're ready to define the relationships on the model. The `Post` and `Video` models will both have a `tags` method that calls the `morphToMany` method on the base Eloquent class: - - morphToMany('App\Tag', 'taggable'); - } - } - -#### Defining The Inverse Of The Relationship - -Next, on the `Tag` model, you should define a method for each of its related models. So, for this example, we will define a `posts` method and a `videos` method: - - morphedByMany('App\Post', 'taggable'); - } - - /** - * Get all of the videos that are assigned this tag. - */ - public function videos() - { - return $this->morphedByMany('App\Video', 'taggable'); - } - } - -#### Retrieving The Relationship - -Once your database table and models are defined, you may access the relationships via your models. For example, to access all of the tags for a post, you can simply use the `tags` dynamic property: - - $post = App\Post::find(1); - - foreach ($post->tags as $tag) { - // - } - -You may also retrieve the owner of a polymorphic relation from the polymorphic model by accessing the name of the method that performs the call to `morphedByMany`. In our case, that is the `posts` or `videos` methods on the `Tag` model. So, you will access those methods as dynamic properties: - - $tag = App\Tag::find(1); - - foreach ($tag->videos as $video) { - // - } - - -## Querying Relations - -Since all types of Eloquent relationships are defined via functions, you may call those functions to obtain an instance of the relationship without actually executing the relationship queries. In addition, all types of Eloquent relationships also serve as [query builders](/docs/{{version}}/queries), allowing you to continue to chain constraints onto the relationship query before finally executing the SQL against your database. - -For example, imagine a blog system in which a `User` model has many associated `Post` models: - - hasMany('App\Post'); - } - } - -You may query the `posts` relationship and add additional constraints to the relationship like so: - - $user = App\User::find(1); - - $user->posts()->where('active', 1)->get(); - -You are able to use any of the [query builder](/docs/{{version}}/queries) methods on the relationship, so be sure to explore the query builder documentation to learn about all of the methods that are available to you. - - -### Relationship Methods Vs. Dynamic Properties - -If you do not need to add additional constraints to an Eloquent relationship query, you may simply access the relationship as if it were a property. For example, continuing to use our `User` and `Post` example models, we may access all of a user's posts like so: - - $user = App\User::find(1); - - foreach ($user->posts as $post) { - // - } - -Dynamic properties are "lazy loading", meaning they will only load their relationship data when you actually access them. Because of this, developers often use [eager loading](#eager-loading) to pre-load relationships they know will be accessed after loading the model. Eager loading provides a significant reduction in SQL queries that must be executed to load a model's relations. - - -### Querying Relationship Existence - -When accessing the records for a model, you may wish to limit your results based on the existence of a relationship. For example, imagine you want to retrieve all blog posts that have at least one comment. To do so, you may pass the name of the relationship to the `has` method: - - // Retrieve all posts that have at least one comment... - $posts = App\Post::has('comments')->get(); - -You may also specify an operator and count to further customize the query: - - // Retrieve all posts that have three or more comments... - $posts = Post::has('comments', '>=', 3)->get(); - -Nested `has` statements may also be constructed using "dot" notation. For example, you may retrieve all posts that have at least one comment and vote: - - // Retrieve all posts that have at least one comment with votes... - $posts = Post::has('comments.votes')->get(); - -If you need even more power, you may use the `whereHas` and `orWhereHas` methods to put "where" conditions on your `has` queries. These methods allow you to add customized constraints to a relationship constraint, such as checking the content of a comment: - - // Retrieve all posts with at least one comment containing words like foo% - $posts = Post::whereHas('comments', function ($query) { - $query->where('content', 'like', 'foo%'); - })->get(); - - -### Counting Related Models - -If you want to count the number of results from a relationship without actually loading them you may use the `withCount` method, which will place a `{relation}_count` column on your resulting models. For example: - - $posts = App\Post::withCount('comments')->get(); - - foreach ($posts as $post) { - echo $post->comments_count; - } - -You may add retrieve the "counts" for multiple relations as well as add constraints to the queries: - - $posts = Post::withCount(['votes', 'comments' => function ($query) { - $query->where('content', 'like', 'foo%'); - }])->get(); - - echo $posts[0]->votes_count; - echo $posts[0]->comments_count; - - -## Eager Loading - -When accessing Eloquent relationships as properties, the relationship data is "lazy loaded". This means the relationship data is not actually loaded until you first access the property. However, Eloquent can "eager load" relationships at the time you query the parent model. Eager loading alleviates the N + 1 query problem. To illustrate the N + 1 query problem, consider a `Book` model that is related to `Author`: - - belongsTo('App\Author'); - } - } - -Now, let's retrieve all books and their authors: - - $books = App\Book::all(); - - foreach ($books as $book) { - echo $book->author->name; - } - -This loop will execute 1 query to retrieve all of the books on the table, then another query for each book to retrieve the author. So, if we have 25 books, this loop would run 26 queries: 1 for the original book, and 25 additional queries to retrieve the author of each book. - -Thankfully, we can use eager loading to reduce this operation to just 2 queries. When querying, you may specify which relationships should be eager loaded using the `with` method: - - $books = App\Book::with('author')->get(); - - foreach ($books as $book) { - echo $book->author->name; - } - -For this operation, only two queries will be executed: - - select * from books - - select * from authors where id in (1, 2, 3, 4, 5, ...) - -#### Eager Loading Multiple Relationships - -Sometimes you may need to eager load several different relationships in a single operation. To do so, just pass additional arguments to the `with` method: - - $books = App\Book::with('author', 'publisher')->get(); - -#### Nested Eager Loading - -To eager load nested relationships, you may use "dot" syntax. For example, let's eager load all of the book's authors and all of the author's personal contacts in one Eloquent statement: - - $books = App\Book::with('author.contacts')->get(); - - -### Constraining Eager Loads - -Sometimes you may wish to eager load a relationship, but also specify additional query constraints for the eager loading query. Here's an example: - - $users = App\User::with(['posts' => function ($query) { - $query->where('title', 'like', '%first%'); - }])->get(); - -In this example, Eloquent will only eager load posts where the post's `title` column contains the word `first`. Of course, you may call other [query builder](/docs/{{version}}/queries) methods to further customize the eager loading operation: - - $users = App\User::with(['posts' => function ($query) { - $query->orderBy('created_at', 'desc'); - }])->get(); - - -### Lazy Eager Loading - -Sometimes you may need to eager load a relationship after the parent model has already been retrieved. For example, this may be useful if you need to dynamically decide whether to load related models: - - $books = App\Book::all(); - - if ($someCondition) { - $books->load('author', 'publisher'); - } - -If you need to set additional query constraints on the eager loading query, you may pass an array keyed by the relationships you wish to load. The array values should be `Closure` instances which receive the query instance: - - $books->load(['author' => function ($query) { - $query->orderBy('published_date', 'asc'); - }]); - - -## Inserting & Updating Related Models - - -### The Save Method - -Eloquent provides convenient methods for adding new models to relationships. For example, perhaps you need to insert a new `Comment` for a `Post` model. Instead of manually setting the `post_id` attribute on the `Comment`, you may insert the `Comment` directly from the relationship's `save` method: - - $comment = new App\Comment(['message' => 'A new comment.']); - - $post = App\Post::find(1); - - $post->comments()->save($comment); - -Notice that we did not access the `comments` relationship as a dynamic property. Instead, we called the `comments` method to obtain an instance of the relationship. The `save` method will automatically add the appropriate `post_id` value to the new `Comment` model. - -If you need to save multiple related models, you may use the `saveMany` method: - - $post = App\Post::find(1); - - $post->comments()->saveMany([ - new App\Comment(['message' => 'A new comment.']), - new App\Comment(['message' => 'Another comment.']), - ]); - - -### The Create Method - -In addition to the `save` and `saveMany` methods, you may also use the `create` method, which accepts an array of attributes, creates a model, and inserts it into the database. Again, the difference between `save` and `create` is that `save` accepts a full Eloquent model instance while `create` accepts a plain PHP `array`: - - $post = App\Post::find(1); - - $comment = $post->comments()->create([ - 'message' => 'A new comment.', - ]); - -Before using the `create` method, be sure to review the documentation on attribute [mass assignment](/docs/{{version}}/eloquent#mass-assignment). - - -### Belongs To Relationships - -When updating a `belongsTo` relationship, you may use the `associate` method. This method will set the foreign key on the child model: - - $account = App\Account::find(10); - - $user->account()->associate($account); - - $user->save(); - -When removing a `belongsTo` relationship, you may use the `dissociate` method. This method will set the relationship's foreign key to `null`: - - $user->account()->dissociate(); - - $user->save(); - - -### Many To Many Relationships - -#### Attaching / Detaching - -Eloquent also provides a few additional helper methods to make working with related models more convenient. For example, let's imagine a user can have many roles and a role can have many users. To attach a role to a user by inserting a record in the intermediate table that joins the models, use the `attach` method: - - $user = App\User::find(1); - - $user->roles()->attach($roleId); - -When attaching a relationship to a model, you may also pass an array of additional data to be inserted into the intermediate table: - - $user->roles()->attach($roleId, ['expires' => $expires]); - -Of course, sometimes it may be necessary to remove a role from a user. To remove a many-to-many relationship record, use the `detach` method. The `detach` method will remove the appropriate record out of the intermediate table; however, both models will remain in the database: - - // Detach a single role from the user... - $user->roles()->detach($roleId); - - // Detach all roles from the user... - $user->roles()->detach(); - -For convenience, `attach` and `detach` also accept arrays of IDs as input: - - $user = App\User::find(1); - - $user->roles()->detach([1, 2, 3]); - - $user->roles()->attach([1 => ['expires' => $expires], 2, 3]); - -#### Syncing Associations - -You may also use the `sync` method to construct many-to-many associations. The `sync` method accepts an array of IDs to place on the intermediate table. Any IDs that are not in the given array will be removed from the intermediate table. So, after this operation is complete, only the IDs in the given array will exist in the intermediate table: - - $user->roles()->sync([1, 2, 3]); - -You may also pass additional intermediate table values with the IDs: - - $user->roles()->sync([1 => ['expires' => true], 2, 3]); - -If you do not want to detach existing IDs, you may use the `syncWithoutDetaching` method: - - $user->roles()->syncWithoutDetaching([1, 2, 3]); - -#### Saving Additional Data On A Pivot Table - -When working with a many-to-many relationship, the `save` method accepts an array of additional intermediate table attributes as its second argument: - - App\User::find(1)->roles()->save($role, ['expires' => $expires]); - -#### Updating A Record On A Pivot Table - -If you need to update an existing row in your pivot table, you may use `updateExistingPivot` method. This method accepts the pivot record foreign key and an array of attributes to update: - - $user = App\User::find(1); - - $user->roles()->updateExistingPivot($roleId, $attributes); - - -## Touching Parent Timestamps - -When a model `belongsTo` or `belongsToMany` another model, such as a `Comment` which belongs to a `Post`, it is sometimes helpful to update the parent's timestamp when the child model is updated. For example, when a `Comment` model is updated, you may want to automatically "touch" the `updated_at` timestamp of the owning `Post`. Eloquent makes it easy. Just add a `touches` property containing the names of the relationships to the child model: - - belongsTo('App\Post'); - } - } - -Now, when you update a `Comment`, the owning `Post` will have its `updated_at` column updated as well, making it more convenient to know when to invalidate a cache of the `Post` model: - - $comment = App\Comment::find(1); - - $comment->text = 'Edit to this comment!'; - - $comment->save(); diff --git a/eloquent-serialization.md b/eloquent-serialization.md deleted file mode 100644 index 5d6a7a4..0000000 --- a/eloquent-serialization.md +++ /dev/null @@ -1,147 +0,0 @@ -# Eloquent: Serialization - -- [Introduction](#introduction) -- [Serializing Models & Collections](#serializing-models-and-collections) - - [Serializing To Arrays](#serializing-to-arrays) - - [Serializing To JSON](#serializing-to-json) -- [Hiding Attributes From JSON](#hiding-attributes-from-json) -- [Appending Values To JSON](#appending-values-to-json) - - -## Introduction - -When building JSON APIs, you will often need to convert your models and relationships to arrays or JSON. Eloquent includes convenient methods for making these conversions, as well as controlling which attributes are included in your serializations. - - -## Serializing Models & Collections - - -### Serializing To Arrays - -To convert a model and its loaded [relationships](/docs/{{version}}/eloquent-relationships) to an array, you should use the `toArray` method. This method is recursive, so all attributes and all relations (including the relations of relations) will be converted to arrays: - - $user = App\User::with('roles')->first(); - - return $user->toArray(); - -You may also convert entire [collections](/docs/{{version}}/eloquent-collections) of models to arrays: - - $users = App\User::all(); - - return $users->toArray(); - - -### Serializing To JSON - -To convert a model to JSON, you should use the `toJson` method. Like `toArray`, the `toJson` method is recursive, so all attributes and relations will be converted to JSON: - - $user = App\User::find(1); - - return $user->toJson(); - -Alternatively, you may cast a model or collection to a string, which will automatically call the `toJson` method on the model or collection: - - $user = App\User::find(1); - - return (string) $user; - -Since models and collections are converted to JSON when cast to a string, you can return Eloquent objects directly from your application's routes or controllers: - - Route::get('users', function () { - return App\User::all(); - }); - - -## Hiding Attributes From JSON - -Sometimes you may wish to limit the attributes, such as passwords, that are included in your model's array or JSON representation. To do so, add a `$hidden` property to your model: - - {note} When hiding relationships, use the relationship's method name, not its dynamic property name. - -Alternatively, you may use the `visible` property to define a white-list of attributes that should be included in your model's array and JSON representation. All other attributes will be hidden when the model is converted to an array or JSON: - - makeVisible('attribute')->toArray(); - -Likewise, if you would like to make some typically visible attributes hidden on a given model instance, you may use the `makeHidden` method. - - return $user->makeHidden('attribute')->toArray(); - - -## Appending Values To JSON - -Occasionally, when casting models to an array or JSON, you may wish to add attributes that do not have a corresponding column in your database. To do so, first define an [accessor](/docs/{{version}}/eloquent-mutators) for the value: - - attributes['admin'] == 'yes'; - } - } - -After creating the accessor, add the attribute name to the `appends` property on the model. Note that attribute names are typically referenced in "snake case", even though the accessor is defined using "camel case": - - -## Introduction +## အကြမ်းဖျင်း -The Eloquent ORM included with Laravel provides a beautiful, simple ActiveRecord implementation for working with your database. Each database table has a corresponding "Model" which is used to interact with that table. Models allow you to query for data in your tables, as well as insert new records into the table. +Laravel တွင်ပါဝင်သည့် ရုုိးရှင်းပြီး လှပသပ်ရပ်သော Eloquent ORM သည် သင့် Database ကုုိ ActiveRecord ဖြင့် အခြေခံထား သဖြင့် အလွယ်တကူပင် အသုုံးပြုနုုိင်မည် ဖြစ်သည်။ Database မှ Table တစ်ခုုတုုိင်းကုုိ Model တစ်ခုု အနေဖြင့် သတ်မှတ်ကာ အသုုံးပြုရမည် ဖြစ်သည်။ -Before getting started, be sure to configure a database connection in `config/database.php`. For more information on configuring your database, check out [the documentation](/docs/{{version}}/database#configuration). +အသုုံးမပြုခင် ပထမဆုုံး အနေဖြင့် `app/config/database.php` သုုိ ့သွားရောက်ကာ ကြိုတင် ပြင်ဆင်ရမည် ဖြစ်သည်။ - -## Defining Models + +## အခြေခံအသုုံးပြုပုုံ -To get started, let's create an Eloquent model. Models typically live in the `app` directory, but you are free to place them anywhere that can be auto-loaded according to your `composer.json` file. All Eloquent models extend `Illuminate\Database\Eloquent\Model` class. +စတင် အသုုံးပြုရန် Eloquent model တစ်ခုုကိုု တည်ဆောက်ရမည် ဖြစ်သည်။ ပုုံမှန်အားဖြင့် Models file များမှာ `app/models` အမည်ရှိသည့် Folder ထဲတွင် တည်ရှိမည် ဖြစ်သော်လည်း အလျဉ်းသင့်သလုုိ ပြင်ဆင်နုုိင်မည်ဖြစ်သည်။ ထုုိသုုိ ့ပြင်ဆင်နုုိင်ရန် အတွက် `composer.json` ထဲတွင် မိမိတုုိ ့ autoload လုုပ်ချင်သည့် file ၏ အမည်နှင့် တည်နေရာကိုု ထည့်သွင်းထားရမည် ဖြစ်သည်။ -The easiest way to create a model instance is using the `make:model` [Artisan command](/docs/{{version}}/artisan): - php artisan make:model User +#### Eloquent Model တစ်ခုု Define ပြုလုုပ်ခြင်း -If you would like to generate a [database migration](/docs/{{version}}/migrations) when you generate the model, you may use the `--migration` or `-m` option: +class User extends Eloquent {} - php artisan make:model User --migration +Eloquent Model တွင် မည့်သည့် table ကုုိ အသုုံးပြုမည်ကုုိ မကြေညာ ထားပါက Model အမည်၏ အများကိန်း ကုုိ အသုုံးပြုမည် ဖြစ်သည်။ ဥပမာ User.php ဟုု ကြေညာထားပါက Users table ဟုု အလုုိအလျောက် သတ်မှတ်မည် ဖြစ်သည်။ သုုိ ့မဟုုတ်ပဲ မိမိ စိတ်ကြိုက် အသုုံးပြုလုုိပါက အောက်ပါ အတုုိင်း သတ်မှတ်နုုိင်မည် ဖြစ်သည်။ - php artisan make:model User -m +class User extends Eloquent { - -### Eloquent Model Conventions +protected $table = 'my_users'; -Now, let's look at an example `Flight` model, which we will use to retrieve and store information from our `flights` database table: +} - **မှတ်ချက်:** Eloquent အနေဖြင့် Primary Key column ဟုု `id` ဟုု အလုုိအလျောက် သတ်မှတ်ဖြစ်သော်လည်း အထက်က ကဲ့သုုိ ့ပင် မိမိစိတ်ကြိုက် column ကုုိ သတ်မှတ်နုုိင်သည်။ ထုုိကဲ့သုုိ ့ Database Connection ကုုိ `connection` ဟုုသည် property ကုုိ အသုုံးပြု ထပ်မံ သတ်မှတ်နုုိင်မည် ဖြစ်သည်။ - namespace App; +Model ကုုိ သတ်မှတ်ပြီးသည်နှင့် မိမိတုုိ ့ အလုုိရှိသည့် record များကုုိ စတင် တည်ဆောက်ခြင်း ၊ ထုုတ်ယူခြင်းများ ပြုလုုပ်နုုိင်ပြီ ဖြစ်သည်။ သတိပြုရမည့် တစ်ချက်မှာ `updated_at` နှင့် `created_at` ဆုုိသည့် columns များမှာ သင့် table တွင် အလုုိအလျောက် ပါဝင်မည်ဖြစ်သည်။ သင့် အနေဖြင့် အလုုိမရှိပါက model အတွင်းရှိ `$timestamps`ဟုုသည် property ကုုိ `false` ဟုု ပေးထားရန် လုုိပေမည်။ - use Illuminate\Database\Eloquent\Model; +#### Model အတွင်းမှ record အားလုုံး ထုုတ်ယူခြင်း - class Flight extends Model - { - // - } +$users = User::all(); +#### Model အတွင်း record များအား primary key ကုုိ အသုုံးပြုကာ ထုုတ်ယူခြင်း -#### Table Names +$user = User::find(1); -Note that we did not tell Eloquent which table to use for our `Flight` model. By convention, the "snake case", plural name of the class will be used as the table name unless another name is explicitly specified. So, in this case, Eloquent will assume the `Flight` model stores records in the `flights` table. You may specify a custom table by defining a `table` property on your model: +var_dump($user->name); - **Note:** [query builder] တွင် အသုုံးပြုနုုိင်သည့် method များ အားလုုံး (queries.md) Eloquent models တွင်လည်း ဆက်လက် အသုုံးပြုနုုိင်မည် ဖြစ်သည်။ - namespace App; +#### Model အတွင်း record များအား primary key ကုုိ အသုုံးပြုကာ ထုုတ်ယူပြီး မရှိပါက Exception ဖြင့် ပြသခြင်း - use Illuminate\Database\Eloquent\Model; +တခါတရံ သင့် အနေဖြင့် Model မှ data များ ရှာမတွေ ့ပါက Exception အနေဖြင့် ပြသချင်မည် ဖြစ်သည်။ ထုုိသုုိ ့ ပြုလုုပ်နိုင်ရန် `App::error` ဟုုသော handler ကုုိ အသုုံးပြုပြီး 404 page ကုုိ လွဲပြောင်းပြသနုုိင်မည် ဖြစ်သည်။ - class Flight extends Model - { - /** - * The table associated with the model. - * - * @var string - */ - protected $table = 'my_flights'; - } +$model = User::findOrFail(1); -#### Primary Keys +$model = User::where('votes', '>', 100)->firstOrFail(); -Eloquent will also assume that each table has a primary key column named `id`. You may define a `$primaryKey` property to override this convention. +To register the error handler, listen for the `ModelNotFoundException` -In addition, Eloquent assumes that the primary key is an incrementing integer value, which means that by default the primary key will be cast to an `int` automatically. If you wish to use a non-incrementing or a non-numeric primary key you must set the public `$incrementing` property on your model to `false`. +use Illuminate\Database\Eloquent\ModelNotFoundException; -#### Timestamps +App::error(function(ModelNotFoundException $e) +{ +return Response::make('Not Found', 404); +}); -By default, Eloquent expects `created_at` and `updated_at` columns to exist on your tables. If you do not wish to have these columns automatically managed by Eloquent, set the `$timestamps` property on your model to `false`: +#### Querying Using Eloquent Models ကုုိ အသုုံးပြုကာ Query များရေးသားခြင်း - ', 100)->take(10)->get(); - namespace App; +foreach ($users as $user) +{ +var_dump($user->name); +} - use Illuminate\Database\Eloquent\Model; +#### Eloquent ကို ပေါင်းစပ် အသုုံးပြုခြင်း - class Flight extends Model - { - /** - * Indicates if the model should be timestamped. - * - * @var bool - */ - public $timestamps = false; - } -If you need to customize the format of your timestamps, set the `$dateFormat` property on your model. This property determines how date attributes are stored in the database, as well as their format when the model is serialized to an array or JSON: +သင့်အနေဖြင့် Query Builder function များဖြင့် Eloquent ကို ပေါင်းစပ် အသုုံးပြုနုုိင်သည်။ - ', 100)->count(); - namespace App; - use Illuminate\Database\Eloquent\Model; +If you are unable to generate the query you need via the fluent interface, feel free to use `whereRaw`: - class Flight extends Model - { - /** - * The storage format of the model's date columns. - * - * @var string - */ - protected $dateFormat = 'U'; - } +$users = User::whereRaw('age > ? and votes = 100', array(25))->get(); -#### Database Connection +#### Results များကို ခွဲထုတ်ခြင်း -By default, all Eloquent models will use the default database connection configured for your application. If you would like to specify a different connection for the model, use the `$connection` property: +သင့်အနေဖြင့် ထောင်ပေါင်းများစွာသော Eloquent records များကို ထုတ်ယူလိုပါက `chunk` ဟုသော method ကို အသုံးပြု၍ Memory အသုံးပြုမှုကို လျော့ချနိုင်ပါသည်။ - -## Retrieving Models +မိမိတို ့ အသုံးပြုလိုသည် Database connection အပေါ်မူတည်၍ `on` method ကို အသုံးပြုကာ ပြောင်းလဲ အသုံးပြုနိုင်ပါသည်။ -Once you have created a model and [its associated database table](/docs/{{version}}/migrations#writing-migrations), you are ready to start retrieving data from your database. Think of each Eloquent model as a powerful [query builder](/docs/{{version}}/queries) allowing you to fluently query the database table associated with the model. For example: +$user = User::on('connection-name')->find(1); - +## အမြောက်အများ ထည့်သွင်းခြင်း - use App\Flight; - $flights = App\Flight::all(); +Model အသစ်ကို တည်ဆောက်ပြီးပါက Constructor အနေဖြင့် ပါဝင်မည့် attribute များကို array အနေဖြင့် ထည့်သွင်းနိုင်ပါသည်။ +ထိုကဲ့သို ့ attribute များ ကို Model များမှ တဆင့် အမြောက်အများ ထည့်သွင်းနိုင်ခြင်းသည် အဆင်ပြေသော်လည်း User Input ကို မစစ်မဆေးပဲ အမြောက်အများထည့်သွင်းပါက လုံခြုံရေး ဆိုင်ရာ **ပြဿနာ** များရှိနိုင်ပါသည်။ ထိုကြောင့် default အနေဖြင့် Eloquent Model များအားလုံးတွင် ထိုသို ့ +ပြုလုပ်ခြင်းကို ဖွင့်မပေးထားပါ။ သို ့သော် ထို ့သို ့ပြုလုပ်ချင်ပါက `fillable` သို ့မဟုတ် `guarded` အစရှိသည့် attribute များကို သတ်မှတ်ထားရန် လိုပေမည်။ - foreach ($flights as $flight) { - echo $flight->name; - } +#### Defining Fillable Attributes On A Model -#### Adding Additional Constraints +The `fillable` property specifies which attributes should be mass-assignable. This can be set at the class or instance level. -The Eloquent `all` method will return all of the results in the model's table. Since each Eloquent model serves as a [query builder](/docs/{{version}}/queries), you may also add constraints to queries, and then use the `get` method to retrieve the results: +class User extends Eloquent { - $flights = App\Flight::where('active', 1) - ->orderBy('name', 'desc') - ->take(10) - ->get(); +protected $fillable = array('first_name', 'last_name', 'email'); -> {tip} Since Eloquent models are query builders, you should review all of the methods available on the [query builder](/docs/{{version}}/queries). You may use any of these methods in your Eloquent queries. +} - -### Collections +အထက်က ဥပမာတွင် array တွင်ထည့်သွင်းထားသည့် attribute များသည် အမြောက်အများ ထည့်သွင်းနိုင်သည်။ -For Eloquent methods like `all` and `get` which retrieve multiple results, an instance of `Illuminate\Database\Eloquent\Collection` will be returned. The `Collection` class provides [a variety of helpful methods](/docs/{{version}}/eloquent-collections#available-methods) for working with your Eloquent results: +#### Model တွင် တားမြစ် attribute များအား သတ်မှတ်ခြင်း - $flights = $flights->reject(function ($flight) { - return $flight->cancelled; - }); -Of course, you may also simply loop over the collection like an array: +`fillable` ၏ ပြောင်းပြန်မှာ `guarded` ဖြစ်ပြီင်္း phone တစ်လုံး၏ "black-list" ကဲ့သို ့ အလုပ်လုပ်သည်။ - foreach ($flights as $flight) { - echo $flight->name; - } +class User extends Eloquent { - -### Chunking Results +protected $guarded = array('id', 'password'); -If you need to process thousands of Eloquent records, use the `chunk` command. The `chunk` method will retrieve a "chunk" of Eloquent models, feeding them to a given `Closure` for processing. Using the `chunk` method will conserve memory when working with large result sets: +} - Flight::chunk(200, function ($flights) { - foreach ($flights as $flight) { - // - } - }); +> **Note:** When using `guarded`, you should still never pass `Input::get()` or any raw array of user controlled input into a `save` or `update` method, as any column that is not guarded may be updated. -The first argument passed to the method is the number of records you wish to receive per "chunk". The Closure passed as the second argument will be called for each chunk that is retrieved from the database. A database query will be executed to retrieve each chunk of records passed to the Closure. +#### အမြောက်အများ ထည့်သွင်းခြင်းမှ တားမြစ်ခြင်း -#### Using Cursors +အပေါ်မှ ဥပမာတွင် `id` နှင့် `password` field များမှာ အမြောက်အများ ထည့်သွင်းနိုင်မည် မဟုတ်ပေ။ အခြား attribute များမှာမူ အမြောက်အများ ထည့်သွင်းနိုင်မည် ဖြစ်သည်။ အကယ်၏ field အားလုံးကို တားမြစ်လိုပါက -The `cursor` method allows you to iterate through your database records using a cursor, which will only execute a single query. When processing large amounts of data, the `cursor` method may be used to greatly reduce your memory usage: +protected $guarded = array('*'); - foreach (Flight::where('foo', 'bar')->cursor() as $flight) { - // - } + +## ထည့်သွင်း ၊ ပြင်ဆင် ၊ ဖျက်ပစ် - -## Retrieving Single Models / Aggregates +Model မှ record အသစ်ကို တည်ဆောက်လိုပါက model instance တစ်ခုကို တည်ဆောက်ပြီး `save` method ကို အသုံးပြုနိုင်သည်။ -Of course, in addition to retrieving all of the records for a given table, you may also retrieve single records using `find` and `first`. Instead of returning a collection of models, these methods return a single model instance: - // Retrieve a model by its primary key... - $flight = App\Flight::find(1); +#### Model တွင် record များ ထည့်သွင်းခြင်း - // Retrieve the first model matching the query constraints... - $flight = App\Flight::where('active', 1)->first(); +$user = new User; -You may also call the `find` method with an array of primary keys, which will return a collection of the matching records: +$user->name = 'John'; - $flights = App\Flight::find([1, 2, 3]); +$user->save(); -#### Not Found Exceptions +> **Note:** Typically, your Eloquent models will have auto-incrementing keys. However, if you wish to specify your own keys, set the `incrementing` property on your model to `false`. -Sometimes you may wish to throw an exception if a model is not found. This is particularly useful in routes or controllers. The `findOrFail` and `firstOrFail` methods will retrieve the first result of the query; however, if no result is found, a `Illuminate\Database\Eloquent\ModelNotFoundException` will be thrown: +You may also use the `create` method to save a new model in a single line. The inserted model instance will be returned to you from the method. However, before doing so, you will need to specify either a `fillable` or `guarded` attribute on the model, as all Eloquent models protect against mass-assignment. - $model = App\Flight::findOrFail(1); +After saving or creating a new model that uses auto-incrementing IDs, you may retrieve the ID by accessing the object's `id` attribute: - $model = App\Flight::where('legs', '>', 100)->firstOrFail(); +$insertedId = $user->id; -If the exception is not caught, a `404` HTTP response is automatically sent back to the user. It is not necessary to write explicit checks to return `404` responses when using these methods: +#### Setting The Guarded Attributes On The Model - Route::get('/api/flights/{id}', function ($id) { - return App\Flight::findOrFail($id); - }); +class User extends Eloquent { - -### Retrieving Aggregates +protected $guarded = array('id', 'account_id'); -You may also use the `count`, `sum`, `max`, and other [aggregate methods](/docs/{{version}}/queries#aggregates) provided by the [query builder](/docs/{{version}}/queries). These methods return the appropriate scalar value instead of a full model instance: +} - $count = App\Flight::where('active', 1)->count(); +#### Using The Model Create Method - $max = App\Flight::where('active', 1)->max('price'); +// Create a new user in the database... +$user = User::create(array('name' => 'John')); - -## Inserting & Updating Models +// Retrieve the user by the attributes, or create it if it doesn't exist... +$user = User::firstOrCreate(array('name' => 'John')); - -### Inserts +// Retrieve the user by the attributes, or instantiate a new instance... +$user = User::firstOrNew(array('name' => 'John')); -To create a new record in the database, simply create a new model instance, set attributes on the model, then call the `save` method: +#### Model တစ်ခုအား Update ပြုလုပ်ခြင်း - email = 'john@foo.com'; - class FlightController extends Controller - { - /** - * Create a new flight instance. - * - * @param Request $request - * @return Response - */ - public function store(Request $request) - { - // Validate the request... +$user->save(); - $flight = new Flight; +#### Model နှင့် ၄င်း၏ Relationship များတွင် save ပြုလုပ်ခြင်း - $flight->name = $request->name; +တခါတရံ သင့်အနေဖြင့် လက်ရှိ အသုံးပြုနေသည့် model တွင်သာ မက ၄င်းနှင့် relationship ပြုလုပ်ထားသော Model များတွင်ပါ save လုပ်လိုသည့် အခါများရှိပေမည်။ ထိုသို ့ ပြုလုပ်လိုပါက `push` method ကို အသုံးပြုနိုင်သည်။ - $flight->save(); - } - } +$user->push(); -In this example, we simply assign the `name` parameter from the incoming HTTP request to the `name` attribute of the `App\Flight` model instance. When we call the `save` method, a record will be inserted into the database. The `created_at` and `updated_at` timestamps will automatically be set when the `save` method is called, so there is no need to set them manually. - -### Updates +You may also run updates as queries against a set of models: -The `save` method may also be used to update models that already exist in the database. To update a model, you should retrieve it, set any attributes you wish to update, and then call the `save` method. Again, the `updated_at` timestamp will automatically be updated, so there is no need to manually set its value: +$affectedRows = User::where('votes', '>', 100)->update(array('status' => 2)); - $flight = App\Flight::find(1); +> **Note:** No model events are fired when updating a set of models via the Eloquent query builder. - $flight->name = 'New Flight Name'; +#### Model မှ record များအား ဖျက်ပစ်ခြင်း - $flight->save(); +record တစ်ခုအား ဖျက်ပစ်လိုပါက `delete` ဟုသော method ကို အသုံးပြုနိုင်သည်။ -#### Mass Updates +$user = User::find(1); -Updates can also be performed against any number of models that match a given query. In this example, all flights that are `active` and have a `destination` of `San Diego` will be marked as delayed: +$user->delete(); - App\Flight::where('active', 1) - ->where('destination', 'San Diego') - ->update(['delayed' => 1]); +#### Model မှ record များအား key အလိုက် ဖျက်ပစ်ခြင်း -The `update` method expects an array of column and value pairs representing the columns that should be updated. +User::destroy(1); -> {note} When issuing a mass update via Eloquent, the `saved` and `updated` model events will be not be fired for the updated models. This is because the models are never actually retrieved when issuing a mass update. +User::destroy(array(1, 2, 3)); - -### Mass Assignment +User::destroy(1, 2, 3); -You may also use the `create` method to save a new model in a single line. The inserted model instance will be returned to you from the method. However, before doing so, you will need to specify either a `fillable` or `guarded` attribute on the model, as all Eloquent models protect against mass-assignment by default. +သင့်အနေဖြင့် query လုပ်ပြီးမှလည်း ဖျက်ပစ်နိုင်ပါသည်။ -A mass-assignment vulnerability occurs when a user passes an unexpected HTTP parameter through a request, and that parameter changes a column in your database you did not expect. For example, a malicious user might send an `is_admin` parameter through an HTTP request, which is then passed into your model's `create` method, allowing the user to escalate themselves to an administrator. +$affectedRows = User::where('votes', '>', 100)->delete(); -So, to get started, you should define which model attributes you want to make mass assignable. You may do this using the `$fillable` property on the model. For example, let's make the `name` attribute of our `Flight` model mass assignable: +#### Model ၏ Timestamps ကိုသာ update ပြုလုပ်ခြင်း - touch(); - use Illuminate\Database\Eloquent\Model; + +## Soft Deleting - class Flight extends Model - { - /** - * The attributes that are mass assignable. - * - * @var array - */ - protected $fillable = ['name']; - } +Soft delete ပြုလုပ်ပါက တကယ်ဖျက်ပစ်လိုက်ခြင်း မဟုတ်ပဲ သင့် record ထဲတွင် `deleted_at` ဟု timestamp တွင် သင့်ဖျက်ပစ်လိုက်သည့် အချိန်ကို မှတ်သားထားမည် ဖြစ်သည်။ Soft delete ကို ထည့်သွင်းလိုပါက `SoftDeletingTrait` ကိုပါ ထည့်သွင်းရမည် ဖြစ်သည်။ -Once we have made the attributes mass assignable, we can use the `create` method to insert a new record in the database. The `create` method returns the saved model instance: +use Illuminate\Database\Eloquent\SoftDeletingTrait; - $flight = App\Flight::create(['name' => 'Flight 10']); +class User extends Eloquent { -#### Guarding Attributes +use SoftDeletingTrait; -While `$fillable` serves as a "white list" of attributes that should be mass assignable, you may also choose to use `$guarded`. The `$guarded` property should contain an array of attributes that you do not want to be mass assignable. All other attributes not in the array will be mass assignable. So, `$guarded` functions like a "black list". Of course, you should use either `$fillable` or `$guarded` - not both. In the example below, all attributes **except for `price`** will be mass assignable: +protected $dates = ['deleted_at']; - softDeletes(); - class Flight extends Model - { - /** - * The attributes that aren't mass assignable. - * - * @var array - */ - protected $guarded = ['price']; - } +ထိုသို ့ပြုလုပ်ပြီး `delete` method ကို ခေါ်ယူပါက အမှန်တကယ် ဖျက်ပစ်မည် မဟုတ်ပဲ `deleted_at` ဟု column တွင် လက်ရှိ timestamp ကိုမှတ်သားထားမည် ဖြစ်သည်။ Model တစ်ခုတွင် soft delete ကို အသုံးပြုထားပါက query ပြုလုပ်သော အခါတိုင်းတွင် deleted record များမှာ ပါဝင်မည် မဟုတ်ပေ။ -If you would like to make all attributes mass assignable, you may define the `$guarded` property as an empty array: +#### Soft Deleted record များပါ ရောစပ်ထုတ်ယူခြင်း - /** - * The attributes that aren't mass assignable. - * - * @var array - */ - protected $guarded = []; - -### Other Creation Methods +soft deleted record များပါ ပေါင်းစပ် ထုတ်ယူလိုပါက `withTrashed` ကို query တွင်ထည့်သွင်း အသုံးပြုရမည် ဖြစ်သည်။ -There are two other methods you may use to create models by mass assigning attributes: `firstOrCreate` and `firstOrNew`. The `firstOrCreate` method will attempt to locate a database record using the given column / value pairs. If the model can not be found in the database, a record will be inserted with the given attributes. +$users = User::withTrashed()->where('account_id', 1)->get(); -The `firstOrNew` method, like `firstOrCreate` will attempt to locate a record in the database matching the given attributes. However, if a model is not found, a new model instance will be returned. Note that the model returned by `firstOrNew` has not yet been persisted to the database. You will need to call `save` manually to persist it: +`withTrashed` method ကို relationship ပြုလုပ်ထားသော model တွင်လည်း အသုံးပြုနိုင်ပါသည်။ - // Retrieve the flight by the attributes, or create it if it doesn't exist... - $flight = App\Flight::firstOrCreate(['name' => 'Flight 10']); +$user->posts()->withTrashed()->get(); - // Retrieve the flight by the attributes, or instantiate a new instance... - $flight = App\Flight::firstOrNew(['name' => 'Flight 10']); +ှSoft deleted ပြုလုပ်ထားသော results များသာ တွေ ့မြင်လိုပါက `onlyTrashed` ဟုသော method ကို အသုံးပြုနိုင်သည်။ - -## Deleting Models +$users = User::onlyTrashed()->where('account_id', 1)->get(); -To delete a model, call the `delete` method on a model instance: +soft deleted ပြုလုပ်ထားသော record များကို restore ပြုလုပ်လိုပါက `restore` method ကို အသုံးပြုနိုင်သည်။ - $flight = App\Flight::find(1); +$user->restore(); - $flight->delete(); +`restore` method ကို query ပြုလုပ်နေသည့် အတောအတွင်းလည်း အသုံးပြုနိုင်သည်။ -#### Deleting An Existing Model By Key +User::withTrashed()->where('account_id', 1)->restore(); -In the example above, we are retrieving the model from the database before calling the `delete` method. However, if you know the primary key of the model, you may delete the model without retrieving it. To do so, call the `destroy` method: - App\Flight::destroy(1); +`withTrashed` ကဲ့သို ့ပင် `restore` method ကိုလည်း relationship များကြားထဲအတွင်း အသုံးပြုနိုင်သည်။ - App\Flight::destroy([1, 2, 3]); +$user->posts()->restore(); - App\Flight::destroy(1, 2, 3); +Record တစ်ခုကို အမှန်တကယ် database ထဲမှ ဖျက်ပစ်လိုပါက `forceDelete` method ကို အသုံးပြုနိုင်သည်။ -#### Deleting Models By Query +$user->forceDelete(); -Of course, you may also run a delete query on a set of models. In this example, we will delete all flights that are marked as inactive. Like mass updates, mass deletes will not fire any model events for the models that are deleted: +`forceDelete` method မှာလည်း relationship များအကြား အသုံးပြုနိုင်သည်။ - $deletedRows = App\Flight::where('active', 0)->delete(); +$user->posts()->forceDelete(); - -### Soft Deleting +soft delted ပြုလုပ်ထားခြင်း ဟုတ်မဟုတ် စစ်ဆေးနိုင်ရန် `trashed` method ကို အသုံးပြုနိုင်သည်။ -In addition to actually removing records from your database, Eloquent can also "soft delete" models. When models are soft deleted, they are not actually removed from your database. Instead, a `deleted_at` attribute is set on the model and inserted into the database. If a model has a non-null `deleted_at` value, the model has been soft deleted. To enable soft deletes for a model, use the `Illuminate\Database\Eloquent\SoftDeletes` trait on the model and add the `deleted_at` column to your `$dates` property: +if ($user->trashed()) +{ +// +} - +## Timestamps - namespace App; +ပုံမှန်အားဖြင့် Eloquent အနေဖြင့် `timestamp` attribute ကိုထည့်သွင်းပေးသည်နှင့် `created_at` and `updated_at` ကို အလိုအလျောက် ကိုင်တွယ်ပေးမည် ဖြစ်သည်။ သင့်အနေနှင့် မလိုချင်ပါက အောက်ပါအတိုင်း ပြောင်းလဲ သတ်မှတ်နိုင်သည်။ - use Illuminate\Database\Eloquent\Model; - use Illuminate\Database\Eloquent\SoftDeletes; +#### အလိုအလျောက် Timestamps ပြုလုပ်ခြင်းမှ ဖယ်ရှားခြင်း - class Flight extends Model - { - use SoftDeletes; +class User extends Eloquent { - /** - * The attributes that should be mutated to dates. - * - * @var array - */ - protected $dates = ['deleted_at']; - } +protected $table = 'users'; -Of course, you should add the `deleted_at` column to your database table. The Laravel [schema builder](/docs/{{version}}/migrations) contains a helper method to create this column: +public $timestamps = false; - Schema::table('flights', function ($table) { - $table->softDeletes(); - }); +} -Now, when you call the `delete` method on the model, the `deleted_at` column will be set to the current date and time. And, when querying a model that uses soft deletes, the soft deleted models will automatically be excluded from all query results. +#### စိတ်ကြိုက် Timestamp တစ်ခုသတ်မှတ်ခြင်း -To determine if a given model instance has been soft deleted, use the `trashed` method: +Timestamp တစ်ခုကို စိတ်ကြိုက်သတ်မှတ်လိုပါက model အတွင်းရှိ `getDateFormat` ကို အသုံးပြု၍ သတ်မှတ်နိုင်သည်။ - if ($flight->trashed()) { - // - } +class User extends Eloquent { - -### Querying Soft Deleted Models +protected function getDateFormat() +{ +return 'U'; +} -#### Including Soft Deleted Models +} -As noted above, soft deleted models will automatically be excluded from query results. However, you may force soft deleted models to appear in a result set using the `withTrashed` method on the query: + +## Query Scopes - $flights = App\Flight::withTrashed() - ->where('account_id', 1) - ->get(); +#### Query Scope တစ်ခုအား သတ်မှတ်ခြင်း -The `withTrashed` method may also be used on a [relationship](/docs/{{version}}/eloquent-relationships) query: +Scope များမှာ သင့်၏ query logic များကို ထပ်ခါထပ်ခါ အသုံးပြုနိုင်ခြင်း ဖြင့် သက်သာစေသည်။ Scope တစ်ခုကို ဖန်တီးနိုင်ရင် `scope` ဟုပါဝင်သည့် +method တစ်ခုကို ဖန်တီးရန် လိုပေမည်။ - $flight->history()->withTrashed()->get(); +class User extends Eloquent { -#### Retrieving Only Soft Deleted Models +public function scopePopular($query) +{ +return $query->where('votes', '>', 100); +} -The `onlyTrashed` method will retrieve **only** soft deleted models: +public function scopeWomen($query) +{ +return $query->whereGender('W'); +} - $flights = App\Flight::onlyTrashed() - ->where('airline_id', 1) - ->get(); +} -#### Restoring Soft Deleted Models +#### Query Scope တစ်ခုအား အသုံးပြုခြင်း -Sometimes you may wish to "un-delete" a soft deleted model. To restore a soft deleted model into an active state, use the `restore` method on a model instance: +$users = User::popular()->women()->orderBy('created_at')->get(); - $flight->restore(); +#### Scopes အရှင်များ ဖန်တီးခြင်း -You may also use the `restore` method in a query to quickly restore multiple models. Again, like other "mass" operations, this will not fire any model events for the models that are restored: +တခါတရံ သင့်အနေဖြင့် parameter များလက်ခံသော scope အရှင်များကို ဖန်တီးလိုပေမည်။ ထိုသို ့ပြုလုပ်နိုင်ရန် သင့်၏ scope function အတွင်းတွင် - App\Flight::withTrashed() - ->where('airline_id', 1) - ->restore(); +class User extends Eloquent { -Like the `withTrashed` method, the `restore` method may also be used on [relationships](/docs/{{version}}/eloquent-relationships): +public function scopeOfType($query, $type) +{ +return $query->whereType($type); +} - $flight->history()->restore(); +} -#### Permanently Deleting Models +ထိုနောက် scope တွင် parameter ကို ထည့်သွင်း အသုံးပြုနိုင်သည်။ -Sometimes you may need to truly remove a model from your database. To permanently remove a soft deleted model from the database, use the `forceDelete` method: +$users = User::ofType('member')->get(); - // Force deleting a single model instance... - $flight->forceDelete(); + +## Relationships - // Force deleting all related models... - $flight->history()->forceDelete(); +Database table များမှာ တခါတရံ တစ်ခုနှင့် တစ်ခု ဆက်စပ်ပြီး တည်ရှိနိုင်ပေသည်။ ဥပမာ Blog post တစ်ခုတွင် comment များစွာ ပါဝင်သကဲ့သို ့ Order တစ်ခုတွင်လည်း User တစ်ယောက်နှင့် ဆက်စပ်နိုင် ပေသည်။ Laravel အနေဖြင့် ဆက်စပ်မှု မျိုးစုံကို ဆောင်ရွက်နိုင်အောင် ကူညီပေးထားပါသည်။ - -## Query Scopes +- [One To One](#one-to-one) +- [One To Many](#one-to-many) +- [Many To Many](#many-to-many) +- [Has Many Through](#has-many-through) +- [Polymorphic Relations](#polymorphic-relations) +- [Many To Many Polymorphic Relations](#many-to-many-polymorphic-relations) + + +### One To One + +#### One To One Relation တစ်ခုကို တည်ဆောက်ခြင်း + +one-to-one relationship မှာ အလွန်ပင် အခြေခံကျသော relation ဖြစ်သည်။ ဥပမာ User တစ်ယောက်တွင် Phone တစ်လုံး ရှိရမည့် အနေအထားမျိုး။ +ထိုသို ့သော relation မျိုးကို Eloquent တွင် ဖန်တီးနိုင်ပေသည်။ + +class User extends Eloquent { + +public function phone() +{ +return $this->hasOne('Phone'); +} + +} + + +`hasOne` တွင်ထည့်သွင်းရမည့် argument မှာ ဆက်စပ်နေသည့် Model ၏ အမည်ပင်ဖြစ်သည်။ relationship တည်ဆောက်ပြီးသည်နှင့် Eloquent ၏ [dynamic properties](#dynamic-properties): ကို အသုံးပြုပြီး အချက်အလက်များကို ထုတ်ယူနိုင်သည်။ + +$phone = User::find(1)->phone; + +အထက်ပါ statement အတွက် run သွားမည့် SQL မှာ အောက်ပါ အတိုင်းဖြစ်သည်။ + +select * from users where id = 1 + +select * from phones where user_id = 1 + +Eloquent အနေဖြင့် model name များကို အခြေခံပြီး Forigen key များကို သတ်မှတ်သွားမည်ကို သတိပြုရမည်။ အထက်က `Phone` model တွင် `user_id` ကို foreign key အနေဖြင့် အလိုအလျောက် သတ်မှတ်မည် ဖြစ်သည်။ မိမိတို ့ စိတ်ကြိုက်ပြောင်းလဲလိုပါက `hasOne` method တွင် ဒုတိယ argument အဖြစ်သွင်းပေးရန် လိုပေမည်။ ထိုထက်ပို၍ တတိယ argument အနေဖြင့် ထည့်သွင်းပါက မည်သည့် local column ကို ပူးပေါင်းမည်ကိုပါ သတ်မှတ်နိုင်သည်။ + +return $this->hasOne('Phone', 'foreign_key'); + +return $this->hasOne('Phone', 'foreign_key', 'local_key'); + +#### Relation ပြောင်းပြန်သတ်မှတ်ခြင်း + +`Phone` model မှ Relation ကို ပြောင်းပြန်အနေဖြင့် သတ်မှတ်လိုပါက `belongsTo` ဟုသည့် method ကို အသုံးပြုနိုင်သည်။ + +class Phone extends Eloquent { + +public function user() +{ +return $this->belongsTo('User'); +} + +} + +အထက်က ဥပမာတွင် Eloquent အနေဖြင့် `phones` table မှ `user_id` column ကို အသုံးပြုမည် ဖြစ်သည်။ `hasMany` ကဲ့သို ့ပင် Foriegn Key ကို သတ်မှတ်လိုပါက ဒုတိယ argument ကို ထည့်သွင်းပေးနိုင်သည်။ + + +class Phone extends Eloquent { + +public function user() +{ +return $this->belongsTo('User', 'local_key'); +} + +} + +ထိုအပြင် parent table နှင့်ဆက်စပ်နေသည့် column ကို တတိယ parameter အဖြစ် ထည့်သွင်းနိုင်သည်။ + +class Phone extends Eloquent { + +public function user() +{ +return $this->belongsTo('User', 'local_key', 'parent_key'); +} + +} + + +### One To Many + +one-to-many relation ၏ ဥပမာမှာ blog post တစ်ခုတွင် comment များစွာ ရှိသကဲ့သို ့ပင် ဖြစ်သည်။ ထိုသို ့ relation ကို အောက်ပါအတိုင်း model တွင် +သတ်မှတ်နိုင်သည်။ + +class Post extends Eloquent { + +public function comments() +{ +return $this->hasMany('Comment'); +} + +} + +ထိုအခါ post comments များကို [dynamic property](#dynamic-properties) ကို အသုံးပြု၍ ထုတ်ယူနိုင်ပါပြီ။ + +$comments = Post::find(1)->comments; + +ထိုထဲမှ ထုတ်ယူလိုသည့် comment များကို စစ်ယူလိုပါက `comments` method နောက်တွင် method များကို စီတန်း အသုံးပြုနိုင်ပါသေးသည်။ + +$comments = Post::find(1)->comments()->where('title', '=', 'foo')->first(); + +၄င်းတွင်လည်း `hasOne` ကဲ့သို ့ foriegn key ကို `hasMany` method နောက်တွင် second argument အနေဖြင့်နှင့် third argument ကို local key အနေဖြင့် ထည့်သွင်းနိုင်ပေသည်။ + +return $this->hasMany('Comment', 'foreign_key'); + +return $this->hasMany('Comment', 'foreign_key', 'local_key'); + +#### ပြောင်းပြန် relation သတ်မှတ်ခြင်း + +`Comment` model ပြောင်းပြန် သတ်မှတ်နိုင်ရန် `belongsTo` ဟုသည့် method ကို အသုံးပြုနိုင်သည်။ + +class Comment extends Eloquent { + +public function post() +{ +return $this->belongsTo('Post'); +} + +} + + +### Many To Many + + +Many-to-many relations မှာ ပိုမိုရှုပ်ထွေးသည့် relation ဖြစ်သည်။ ဥပမာ User တစ်ယောက်မှာ တာဝန်များစွာ ရှိပြီး တာဝန်တစ်ခုကိုလည်း User များစွာ ခွဲဝေပေးအပ်ထားသည် ဆိုပါစို ့။ User များစွာ "Admin" တာဝန်ကို ယူထားနိုင်သည့် အခြေအနေတွင်ရှိပေမည်။ ထိုသို ့သော အခြေအနေတွင် Database +Table သုံးခု လိုအပ်မည် ဖြစ်သည်။ ၄င်းတို ့မှာ `users` ၊ `roles` နှင့် `role_user` တို ့ဖြစ်ကြသည်။ `role_user` table မှာ ဆက်စပ်နေသည့် model အမည်များကို ဆက်စပ်ပေးမည် ဖြစ်ပြီး ၄င်းတွင် `user_id` နှင့် `role_id` ဟူသော columns နှစ်ခု ပါဝင်မည် ဖြစ်သည်။ + + +many-to-many relation ကို `belongsToMany` method ကို အသုံးပြု၍ ရေးသားနိုင်သည်။ + +class User extends Eloquent { + +public function roles() +{ +return $this->belongsToMany('Role'); +} + +} + +ထိုအခါ `User` မှ role ကို အောက်ပါ အတိုင်း ထုတ်ယူနိုင်မည် ဖြစ်သည်။ + +$roles = User::find(1)->roles; + +မိမိ၏ ကြားခံ table ၏ အမည်ကို စိတ်ကြိုက် သတ်မှတ်လိုပါက `belongsToMany` method ၏ ဒုတိယ argument မှ သွင်း၍ စိတ်ကြိုက် သတ်မှတ်နိုင်သည်။ + +return $this->belongsToMany('Role', 'user_roles'); + +ထိုအပြင် ပါဝင်ပတ်သတ်နေသော Keys များကိုလည်း စိတ်ကြိုက် သတ်မှတ်နိုင်သည်။ + +return $this->belongsToMany('Role', 'user_roles', 'user_id', 'foo_id'); + +ထိုအပြင် `Role` model မှလည်း ပြောင်းပြန်သတ်မှတ် ၍လည်း ဖြစ်ပါသည်။ + +class Role extends Eloquent { + +public function users() +{ +return $this->belongsToMany('User'); +} + +} + + +### Has Many Through + + "has many through" ဝေးကွာနေသည့် relation များမှ record များကို access လုပ်နိုင်ရန် အလွယ်တကူ ကြားဖြတ်ဆောင်ရွက်ပေးသော method ဇြစ်သည်။ ဥပမာ `Country` model မှာ `Posts` ဖြင့် ချိတ်ဆက်ထားခြင်း မရှိသော်လည်း `Users` model ဖြင့်မူ ချိတ်ဆက်ထားပါက တဆင့်ကျော်၍ access လုပ်နိုင်သည်။ ထို table များ၏ relationship မှာ အောက်ပါအတိုင်း ဆိုပါစို ့ + +countries +id - integer +name - string + +users +id - integer +country_id - integer +name - string + +posts +id - integer +user_id - integer +title - string + +`posts` table တွင် `country_id` column မပါဝင်သော်လည်း `hasManyThrough` relation ဖြင့် `$country->posts` ဟု၍ accessible ဖြစ်အောင် စွမ်းဆောင်နိုင်ပေသည်။ + +class Country extends Eloquent { + +public function posts() +{ +return $this->hasManyThrough('Post', 'User'); +} + +} + +relationship key များကို စိတ်ကြိုက်သတ်မှတ်လိုပါက တတိယနှင့် စတုတ္ထ parameter အများအဖြစ် ထည့်သွင်းနိုင်ပေသည်။ + +class Country extends Eloquent { + +public function posts() +{ +return $this->hasManyThrough('Post', 'User', 'country_id', 'user_id'); +} + +} + + +### Polymorphic Relations + +Polymorphic relations ကို အသုံးပြုခြင်းဖြင့် အခြား Model တစ်ခုထက်ပို၍ associate ပြုလုပ်ထားသော record များကို ထုတ်ယူနိုင်သည်။ ဥပမာ သင့်တွင် +staff ဟုသော model နှင့် order ဟုသော model နှစ်ခုလုံးနှင့် ပတ်သတ်နေသည့် photo ဟုသော model ရှိသည် ဆိုပါစို ့။ + + +class Photo extends Eloquent { + +public function imageable() +{ +return $this->morphTo(); +} + +} + +class Staff extends Eloquent { + +public function photos() +{ +return $this->morphMany('Photo', 'imageable'); +} + +} + +class Order extends Eloquent { + +public function photos() +{ +return $this->morphMany('Photo', 'imageable'); +} + +} + +#### Polymorphic Relation ကို အသုံးပြုခြင်း + +အောက်ပါ အတိုင်း photo များကို Staff member များမှသော်လည်းကောင်း Order မှသော်လည်းကောင်း ထုတ်ယူနိုင်သည်။ + +$staff = Staff::find(1); + +foreach ($staff->photos as $photo) +{ +// +} + +#### Polymorphic Relation မှ Owner ၏ record များကို ထုတ်ယူခြင်း + +သို ့သော် တကယ့် "polymorphic" အလှတရားမှာ `Photo` model မှ staff ဖြစ်စေ ၊ order ဖြစ်စေ ထုတ်ယူနိုင်ခြင်း ဖြစ်သည်။ + + +$photo = Photo::find(1); + +$imageable = $photo->imageable; + +`Photo` model မှ `imageable` relation မှာ `Staff` မှဖြစ်စေ `Order` instance ဖြစ်စေ ပိုင်ဆိုင်သည့် model ပေါ်မူတည်၍ ထုတ်ပေးသွားမည် ဖြစ်သည်။ + +#### Polymorphic Relation Table Structure + +မည်သို ့မည်ပုံ အလုပ်လုပ်ဆောင်သွားသည်ကို သိရှိနိုင်ရန် အောက်ပါ database structure ကို ကြည့်ရှုနိုင်ပါသည်။ + +staff +id - integer +name - string + +orders +id - integer +price - integer + +photos +id - integer +path - string +imageable_id - integer +imageable_type - string + +Key field အနေဖြင့် `photos` table မှ `imageable_id` နှင့် `imageable_type` တို ့ကို မှတ်သားထားရပါမည် ဖြစ်သည်။ ID မှာ Order သို ့မဟုတ် +Staff တို ့၏ ID နှင့် ချိတ်ဆက်ထားမည် ဖြစ်သည်။ ORM အနေဖြင့် မည်သည့် model ကိုပြန်ရမည် ဆိုသည်ကို `imageable` ၏ relation ကို ထောက်ရှု၍ လုပ်ဆောင် သွားမည် ဖြစ်သည်။ + + +### Many To Many Polymorphic Relations + +#### Polymorphic Many To Many Relation Table Structure + +သမရိုးကျ polymorphic relations တစ်ခုသာမက many-to-many polymorphic relations များကိုပါ တည်ဆောက်နိုင်သည်။ ဥပမာ blog တစ်ခု၏ database structure ဖြစ်သော `Post` နှင့် `Video` model တို ့တွင် `Tag` model ကို တူညီစွာ polymorphic relation အနေဖြင့် ချိတ်ဆက်ရန် လိုပေမည်။ ရှေဦးစွာ table structure ကိုကြည့်လိုက်ပါ။ + +posts +id - integer +name - string + +videos +id - integer +name - string + +tags +id - integer +name - string + +taggables +tag_id - integer +taggable_id - integer +taggable_type - string + +အထက်ပါ table အတွက် relationship များကို model တွင် အောက်ပါအတိုင်း တည်ဆောက်ရမည်ဖြစ်သည်။ `Post` နှင့် `Video` model တို ့နှစ်ခုလုံးတွင် +`tags` method မှ `morphToMany` relationship ကို ကြေညာပေးရမည် ဖြစ်သည်။ + +class Post extends Eloquent { + +public function tags() +{ +return $this->morphToMany('Tag', 'taggable'); +} + +} + +`Tag` model အနေဖြင့် ၄င်း၏ relationships ကို အောက်ပါ အတိုင်း သတ်မှတ်နိုင်သည်။ + +class Tag extends Eloquent { + +public function posts() +{ +return $this->morphedByMany('Post', 'taggable'); +} + +public function videos() +{ +return $this->morphedByMany('Video', 'taggable'); +} + +} + + +## Relation များကို Query ပြုလုပ်ခြင်း + +#### Relations များတွင် Select ကို အသုံးပြုခြင်း + +Model များမှ record များကို access ပြုလုပ်ရာတွင် ၊ result များကို စစ်ဆေးပြီးမှ ထုတ်ယူလိုသည့် အနေအထားမျိုးတွင် ရှိပေနိုင်သည်။ ဥပမာ သင့်အနေဖြင့် Comment တစ်ခု အနည်းဆုံး ရှိသည့် blog post များကို ဆွဲထုတ်လိုသည် ဆိုပါစို ့။ သင့်အနေနဲ ့ `has` method ကို အသုံးပြုရမည် ဖြစ်သည်။ + +$posts = Post::has('comments')->get(); + +has method တွင် သင့်အနေဖြင့် operator များ နှင့် ထုတ်ယူလိုသည့် အရေအတွက်ကို သတ်မှတ်နိုင်သည်။ + +$posts = Post::has('comments', '>=', 3)->get(); + +သင့်အနေဖြင့် ပို၍ အသေးစိတ်ကျပြီး "where" conditions များကို `has` queries အတွင်း စစ်ဆေးလိုပါက `whereHas` နှင့် `orWhereHas` method များကိုအသုံးပြုနိုင်သည်။ + +$posts = Post::whereHas('comments', function($q) +{ +$q->where('content', 'like', 'foo%'); + +})->get(); + + +### Dynamic Properties + + +Eloquent တွင် သင့်အနေဖြင့် relations များမှ properties များကို dynamic properties အနေဖြင့် ဆွဲယူနိုင်သည်။ Eloquent အနေဖြင့် သင့်၏ relationship အလိုအလျောက်အနေဖြင့် relations ကို အလိုအလျောက် load လုပ်ကာ ခေါ်ယူမည် ဖြစ်ပြီး `get` ( one-to-many relationships) ပေလော၊ `first` (for one-to-one relationships) method ပေလော ကိုပင် ခွဲခြားလုပ်ဆောင်ပေးမည် ဖြစ်သည်။ ထိုနောက် တူညီသော အမည်မှ တဆင့် +dynamic property ကို အလွယ်တကူ ခေါ်ဆို နိုင်ပေမည်။ ဥပမာ `$phone` ဟုသည့် model မှ တဆင့် + +class Phone extends Eloquent { + +public function user() +{ +return $this->belongsTo('User'); +} + +} + +$phone = Phone::find(1); + +Instead of echoing the user's email like this: + +echo $phone->user()->first()->email; + +It may be shortened to simply: + +echo $phone->user->email; + +> **Note:** Relationships များကို return ပြန်သော result များကို အလုပ်လုပ်သွားသော method မှာ `Illuminate\Database\Eloquent\Collection` class မှ instance များကို ပြန်ခြင်းဖြစ်သည်။ + + +## Eager Loading + + +Eager loading exists to N+1 query ကဲ့သို ့သော Query များကို ပို ့၍ ပေါ့ပါးစွာ အသုံးပြုနိုင်ရန် ဖြစ်သည်။ ဥပမာ `Author` model နှင့် `Book` model တို ့ ဆက်စပ်နေသည် ဆိုပါစို ့။ ၄င်းတို ့၏ relationship ကို အောက်ပါ အတိုင်း သတ်မှတ်နိုင်ပါသည်။ + +class Book extends Eloquent { + +public function author() +{ +return $this->belongsTo('Author'); +} + +} + +ထိုနောက် အောက်ပါ code ကို ကြည့်ကြည့်ပါ။ + +foreach (Book::all() as $book) +{ +echo $book->author->name; +} + +ထို loop မှာ Book မှ ရှိသမျှ စာအုပ်တိုင်းကို ခေါ်ယူမည် ဖြစ်သည်။ ထိုနောက် ထိုနောက် ထိုနောက် နောက် query တစ်ခုအနေဖြင့် စာအုပ်တစ်ခုချင်းဆီ၏ +author ကို ဖော်ပြသွားမည် ဖြစ်သည်။ အကယ်၍ စာအုပ် ၂၅ အုပ် ရှိသည် ဆိုပါစို ့ ၊ query ၂၆ ကြောင်း run ဖြစ်သည်။ သို ့ပင်သော်ညား eager loading ၏ အကျိုးကျေးဇူးကြောင့် မလိုအပ်သော query များကို လျှော့ချနိုင်သည်။ ထို relationship တွင် `with` method အသုံးပြု၍ eager load ပြုလုပ်နိုင်သည်။ + + +foreach (Book::with('author')->get() as $book) +{ +echo $book->author->name; +} + +အထက်ပါ loop တွင်မူ query နှစ်ကြောင်းသာ execute ပြုလုပ်မည် ဖြစ်သည်။ + +select * from books + +select * from authors where id in (1, 2, 3, 4, 5, ...) + +Eager loading ကို အသုံးပြုခြင်း အားဖြင့် သင့် application ၏ performance ကို သိသိသာသာ မြင့်တက်စေမည် ဖြစ်သည်။ + +ထိုအပြင် တစ်ခုထက်ပိုသော relation များတွင် တချိန်တည်းတွင် eager load အသုံးပြုနိုင်မည် ဖြစ်သည်။ + +$books = Book::with('author', 'publisher')->get(); + +Nested relationship များတွင်လည်း eager load အသုံးပြုနိုင်သည်။ + +$books = Book::with('author.contacts')->get(); + +အထက် ဥပမာ တွင် `author` နှင့် ပတ်သတ်နေသည်များကို eager load ပြုလုပ်ပြီး author ၏ `contacts` relation ပါ load သွားမည် ဖြစ်သည်။ + +### Eager Load အကန် ့အသတ်များ + +ထခါတရံ condition များ စစ်ဆေးပြီးမှ relationship များကို eager load ပြုလုပ်လိုမည် အချိန်ကာလ လည်း ရှိပေမည်။ အောက်က ဥပမာတွင် ဆိုပါစို ့ + +$users = User::with(array('posts' => function($query) +{ +$query->where('title', 'like', '%first%'); + +}))->get(); + +ထို ဥပမာ တွင် user's post တွင်းမှ "first" စကာလုံး နှင့်စတင်သည်များကိုသာ eager load လုပ်သွားမည် ဖြစ်သည်။ Closure များ အတွင်းတွင်မူ အကန့် အသတ်မရှိပေ။ သင့်အနေဖြင့် အောက်က အတိုင်း order အလိုက် စီရီနိုင်ပေဦးမည်။ + +$users = User::with(array('posts' => function($query) +{ +$query->orderBy('created_at', 'desc'); + +}))->get(); + +### Lazy Eager Loading + +တည်ရှိနေပြီးသော model collection များထဲမှ eager load နှင့် ဆက်စပ်နေသော model များကို တိုက်ရိုက် ခေါ်ယူ၍လည်း ဖြစ်နိုင်ပေသည်။ ထိုသို ့ပြုလုပ်ခြင်း Model များကို Load လုပ်ရာတွင် load လုပ်မည် မလုပ်မည်ကို dynamically စဉ်းစားဆုံးဖြတ်ရာတွင် သော်လည်းကောင်း ၊ caching ဖြင့် ပူးပေါင်း အသုံးပြုရာတွင်သော်လည်းကောင်း အသုံးဝင်သည်။ + +$books = Book::all(); + +$books->load('author', 'publisher'); + + +## ဆက်စပ်နေသည့် Model များတွင် data ထည့်သွင်းခြင်း + +#### ဆက်စပ်နေသည့် Model ဖြင့် ချိတ်ဆက်ခြင်း + +တခါတရံ ဆက်စပ်နေသည့် model များအား insert ပြုလုပ်ရန်လည်း လိုပေမည်။ ဥပမာ သင့်အနေဖြင့် post တစ်ခုတွင် comment တစ်ခုကို ထည့်သွင်းမည် ဆိုပါစို ့။ Model တစ်ခု၏ `post_id` foreign key ကို manually ထည့်သွင်းနေမည့် အစား `Post` model ဖက်မှ တိုက်ရိုက်ထည့်သွင်း၍လည်း ရပေသည်။ + +$comment = new Comment(array('message' => 'A new comment.')); + +$post = Post::find(1); + +$comment = $post->comments()->save($comment); + +အထက်က ဥပမာတွင် `post_id` field ကို အလိုအလျောက် ထည့်သွင်းသွားမည် ဖြစ်သည်။ + +### Models များ ဆက်စပ်ခြင်း(Belongs To) + +`belongsTo` relationship ဖြင့် Method များကို data များ update လုပ်စေလိုပါက `associate` method ကို အသုံးပြုနိုင်သည်။ ထို method သည် လက်အောက်ခံ model ၏ foregin key ကိုပါ ထည့်သွင်းပေးသွားမည် ဖြစ်သည်။ + +$account = Account::find(10); + +$user->account()->associate($account); + +$user->save(); + +### ဆက်စပ်နေသည့် Model တွင် data ထည့်သွင်းခြင်း (Many To Many) + +သင့်အနေဖြင့် many-to-many relations ရှိနေသည့် model များတွင်လည်း data ဖြည့်သွင်းလိုပေမည်။ ထုံးစံ ဥပမာ တစ်ခုဖြစ်သည့် `User` နှင့် `Role` model များဖြင့် ရှေ ့ဆက်ကြစို ့။ user ၏ roles များကို `attach` method ဖြင့် ချိတ်ဆက်နိုင်သည်။ + +#### Attaching Many To Many Models + +$user = User::find(1); + +$user->roles()->attach(1); + +You may also pass an array of attributes that should be stored on the pivot table for the relation: + +$user->roles()->attach(1, array('expires' => $expires)); + +Of course, the opposite of `attach` is `detach`: + +$user->roles()->detach(1); + +#### Using Sync To Attach Many To Many Models + +You may also use the `sync` method to attach related models. The `sync` method accepts an array of IDs to place on the pivot table. After this operation is complete, only the IDs in the array will be on the intermediate table for the model: + +$user->roles()->sync(array(1, 2, 3)); + +#### Adding Pivot Data When Syncing + +You may also associate other pivot table values with the given IDs: + +$user->roles()->sync(array(1 => array('expires' => true))); + +Sometimes you may wish to create a new related model and attach it in a single command. For this operation, you may use the `save` method: + +$role = new Role(array('name' => 'Editor')); + +User::find(1)->roles()->save($role); + +In this example, the new `Role` model will be saved and attached to the user model. You may also pass an array of attributes to place on the joining table for this operation: + +User::find(1)->roles()->save($role, array('expires' => $expires)); + + +## Touching Parent Timestamps + +When a model `belongsTo` another model, such as a `Comment` which belongs to a `Post`, it is often helpful to update the parent's timestamp when the child model is updated. For example, when a `Comment` model is updated, you may want to automatically touch the `updated_at` timestamp of the owning `Post`. Eloquent makes it easy. Just add a `touches` property containing the names of the relationships to the child model: + +class Comment extends Eloquent { + +protected $touches = array('post'); + +public function post() +{ +return $this->belongsTo('Post'); +} + +} + +Now, when you update a `Comment`, the owning `Post` will have its `updated_at` column updated: + +$comment = Comment::find(1); + +$comment->text = 'Edit to this comment!'; + +$comment->save(); + + +## Working With Pivot Tables + +As you have already learned, working with many-to-many relations requires the presence of an intermediate table. Eloquent provides some very helpful ways of interacting with this table. For example, let's assume our `User` object has many `Role` objects that it is related to. After accessing this relationship, we may access the `pivot` table on the models: + +$user = User::find(1); + +foreach ($user->roles as $role) +{ +echo $role->pivot->created_at; +} + +Notice that each `Role` model we retrieve is automatically assigned a `pivot` attribute. This attribute contains a model representing the intermediate table, and may be used as any other Eloquent model. + +By default, only the keys will be present on the `pivot` object. If your pivot table contains extra attributes, you must specify them when defining the relationship: + +return $this->belongsToMany('Role')->withPivot('foo', 'bar'); + +Now the `foo` and `bar` attributes will be accessible on our `pivot` object for the `Role` model. + +If you want your pivot table to have automatically maintained `created_at` and `updated_at` timestamps, use the `withTimestamps` method on the relationship definition: + +return $this->belongsToMany('Role')->withTimestamps(); + +#### Deleting Records On A Pivot Table + +To delete all records on the pivot table for a model, you may use the `detach` method: + +User::find(1)->roles()->detach(); + +Note that this operation does not delete records from the `roles` table, but only from the pivot table. + +#### Updating A Record On A Pivot Table + +Sometimes you may need to update your pivot table, but not detach it. If you wish to update your pivot table in place you may use `updateExistingPivot` method like so: + +User::find(1)->roles()->updateExistingPivot($roleId, $attributes); + +#### Defining A Custom Pivot Model + +Laravel also allows you to define a custom Pivot model. To define a custom model, first create your own "Base" model class that extends `Eloquent`. In your other Eloquent models, extend this custom base model instead of the default `Eloquent` base. In your base model, add the following function that returns an instance of your custom Pivot model: + +public function newPivot(Model $parent, array $attributes, $table, $exists) +{ +return new YourCustomPivot($parent, $attributes, $table, $exists); +} + + +## Collections + +All multi-result sets returned by Eloquent, either via the `get` method or a `relationship`, will return a collection object. This object implements the `IteratorAggregate` PHP interface so it can be iterated over like an array. However, this object also has a variety of other helpful methods for working with result sets. + +#### Checking If A Collection Contains A Key + +For example, we may determine if a result set contains a given primary key using the `contains` method: + +$roles = User::find(1)->roles; + +if ($roles->contains(2)) +{ +// +} + +Collections may also be converted to an array or JSON: + +$roles = User::find(1)->roles->toArray(); + +$roles = User::find(1)->roles->toJson(); + +If a collection is cast to a string, it will be returned as JSON: + +$roles = (string) User::find(1)->roles; + +#### Iterating Collections + +Eloquent collections also contain a few helpful methods for looping and filtering the items they contain: + +$roles = $user->roles->each(function($role) +{ +// +}); + +#### Filtering Collections + +When filtering collections, the callback provided will be used as callback for [array_filter](http://php.net/manual/en/function.array-filter.php). + +$users = $users->filter(function($user) +{ +return $user->isAdmin(); +}); + +> **Note:** When filtering a collection and converting it to JSON, try calling the `values` function first to reset the array's keys. + +#### Applying A Callback To Each Collection Object + +$roles = User::find(1)->roles; + +$roles->each(function($role) +{ +// +}); + +#### Sorting A Collection By A Value + +$roles = $roles->sortBy(function($role) +{ +return $role->created_at; +}); + +#### Sorting A Collection By A Value + +$roles = $roles->sortBy('created_at'); + +#### Returning A Custom Collection Type + +Sometimes, you may wish to return a custom Collection object with your own added methods. You may specify this on your Eloquent model by overriding the `newCollection` method: + +class User extends Eloquent { + +public function newCollection(array $models = array()) +{ +return new CustomCollection($models); +} + +} + + +## Accessors & Mutators + +#### Defining An Accessor + +Eloquent provides a convenient way to transform your model attributes when getting or setting them. Simply define a `getFooAttribute` method on your model to declare an accessor. Keep in mind that the methods should follow camel-casing, even though your database columns are snake-case: + +class User extends Eloquent { + +public function getFirstNameAttribute($value) +{ +return ucfirst($value); +} - -### Global Scopes +} -Global scopes allow you to add constraints to all queries for a given model. Laravel's own [soft delete](#soft-deleting) functionality utilizes global scopes to only pull "non-deleted" models from the database. Writing your own global scopes can provide a convenient, easy way to make sure every query for a given model receives certain constraints. +In the example above, the `first_name` column has an accessor. Note that the value of the attribute is passed to the accessor. -#### Writing Global Scopes +#### Defining A Mutator -Writing a global scope is simple. Define a class that implements the `Illuminate\Database\Eloquent\Scope` interface. This interface requires you to implement one method: `apply`. The `apply` method may add `where` constraints to the query as needed: +Mutators are declared in a similar fashion: - attributes['first_name'] = strtolower($value); +} - use Illuminate\Database\Eloquent\Scope; - use Illuminate\Database\Eloquent\Model; - use Illuminate\Database\Eloquent\Builder; +} - class AgeScope implements Scope - { - /** - * Apply the scope to a given Eloquent query builder. - * - * @param \Illuminate\Database\Eloquent\Builder $builder - * @param \Illuminate\Database\Eloquent\Model $model - * @return void - */ - public function apply(Builder $builder, Model $model) - { - return $builder->where('age', '>', 200); - } - } + +## Date Mutators -> {tip} There is not a predefined folder for scopes in a default Laravel application, so feel free to make your own `Scopes` folder within your Laravel application's `app` directory. +By default, Eloquent will convert the `created_at`, `updated_at`, and `deleted_at` columns to instances of [Carbon](https://github.com/briannesbitt/Carbon), which provides an assortment of helpful methods, and extends the native PHP `DateTime` class. -#### Applying Global Scopes +You may customize which fields are automatically mutated, and even completely disable this mutation, by overriding the `getDates` method of the model: -To assign a global scope to a model, you should override a given model's `boot` method and use the `addGlobalScope` method: +public function getDates() +{ +return array('created_at'); +} - +## Model Events - static::addGlobalScope(new AgeScope); - } - } +Eloquent models fire several events, allowing you to hook into various points in the model's lifecycle using the following methods: `creating`, `created`, `updating`, `updated`, `saving`, `saved`, `deleting`, `deleted`, `restoring`, `restored`. -After adding the scope, a query to `User::all()` will produce the following SQL: +Whenever a new item is saved for the first time, the `creating` and `created` events will fire. If an item is not new and the `save` method is called, the `updating` / `updated` events will fire. In both cases, the `saving` / `saved` events will fire. - select * from `users` where `age` > 200 +#### Cancelling Save Operations Via Events -#### Anonymous Global Scopes +If `false` is returned from the `creating`, `updating`, `saving`, or `deleting` events, the action will be cancelled: -Eloquent also allows you to define global scopes using Closures, which is particularly useful for simple scopes that do not warrant a separate class: +User::creating(function($user) +{ +if ( ! $user->isValid()) return false; +}); - where('age', '>', 200); - }); - } - } +// Setup event bindings... +} -The first argument of the `addGlobalScope()` serves as an identifier to remove the scope: +} - User::withoutGlobalScope('age')->get(); + +## Model Observers -#### Removing Global Scopes +To consolidate the handling of model events, you may register a model observer. An observer class may have methods that correspond to the various model events. For example, `creating`, `updating`, `saving` methods may be on an observer, in addition to any other model event name. -If you would like to remove a global scope for a given query, you may use the `withoutGlobalScope` method. The method accepts the class name of the global scope as its only argument: +So, for example, a model observer might look like this: - User::withoutGlobalScope(AgeScope::class)->get(); +class UserObserver { -If you would like to remove several or even all of the global scopes, you may use the `withoutGlobalScopes` method: +public function saving($model) +{ +// +} - // Remove all of the global scopes... - User::withoutGlobalScopes()->get(); +public function saved($model) +{ +// +} - // Remove some of the global scopes... - User::withoutGlobalScopes([ - FirstScope::class, SecondScope::class - ])->get(); +} - -### Local Scopes +You may register an observer instance using the `observe` method: -Local scopes allow you to define common sets of constraints that you may easily re-use throughout your application. For example, you may need to frequently retrieve all users that are considered "popular". To define a scope, simply prefix an Eloquent model method with `scope`. +User::observe(new UserObserver); -Scopes should always return a query builder instance: + +## Arrays နှင့် JSON သို ့ပြောင်းလဲခြင်း - first(); - class User extends Model - { - /** - * Scope a query to only include popular users. - * - * @return \Illuminate\Database\Eloquent\Builder - */ - public function scopePopular($query) - { - return $query->where('votes', '>', 100); - } +return $user->toArray(); - /** - * Scope a query to only include active users. - * - * @return \Illuminate\Database\Eloquent\Builder - */ - public function scopeActive($query) - { - return $query->where('active', 1); - } - } +Models connection တစ်ခုလုံးပါ array အဖြစ် ပြောင်းလဲသွားသည်ကို သတိပြုရမည်။ -#### Utilizing A Local Scope +return User::all()->toArray(); -Once the scope has been defined, you may call the scope methods when querying the model. However, you do not need to include the `scope` prefix when calling the method. You can even chain calls to various scopes, for example: +#### Model တစ်ခုကို JSON သို ့ ပြောင်းလဲခြင်း - $users = App\User::popular()->active()->orderBy('created_at')->get(); +Model တစ်ခုကို JSON အနေဖြင့် ပြောင်းလဲလိုပါက `toJson` method ကို အသုံးပြုနိုင်သည်။ -#### Dynamic Scopes +return User::find(1)->toJson(); -Sometimes you may wish to define a scope that accepts parameters. To get started, just add your additional parameters to your scope. Scope parameters should be defined after the `$query` parameter: +#### Route တစ်ခုမှ Model ကို return ပြန်ခြင်း - where('type', $type); - } - } +တခါတရံ သင့်အနေဖြင့် တချို ့သော attribute များကို array သို ့မဟုတ် JSON သို ့ပြောင်းလဲရာတွင် ပါမလာ စေချင်သည့် attribute များ (ဥပမာ password များကဲ့သို ့သော ) ရှိပေမည်။ ထိုသို ့ပြုလုပ်နိုင်ရန် model အတွင်းတွင် `hidden` ဟူသော property တစ်ခုအဖြစ် ကြေညာပေးရန် လိုပေမည်။ -Now, you may pass the parameters when calling the scope: +class User extends Eloquent { - $users = App\User::ofType('admin')->get(); +protected $hidden = array('password'); - -## Events +} -Eloquent models fire several events, allowing you to hook into various points in the model's lifecycle using the following methods: `creating`, `created`, `updating`, `updated`, `saving`, `saved`, `deleting`, `deleted`, `restoring`, `restored`. Events allow you to easily execute code each time a specific model class is saved or updated in the database. +> **Note:** When hiding relationships, use the relationship's **method** name, not the dynamic accessor name. -Whenever a new model is saved for the first time, the `creating` and `created` events will fire. If a model already existed in the database and the `save` method is called, the `updating` / `updated` events will fire. However, in both cases, the `saving` / `saved` events will fire. +အပြန်အလှန်အားဖြင့် သင့်အနေဖြင့် ထုတ်ချင်သည်များကိုသာ ဖော်ပြနိုင်ရန် `visible` ဟုသည် property တစ်ခု ကြေညာနိုင်ပေသည်။ -For example, let's define an Eloquent event listener in a [service provider](/docs/{{version}}/providers). Within our event listener, we will call the `isValid` method on the given model, and return `false` if the model is not valid. Returning `false` from an Eloquent event listener will cancel the `save` / `update` operation: +protected $visible = array('first_name', 'last_name'); - +Occasionally, you may need to add array attributes that do not have a corresponding column in your database. To do so, simply define an accessor for the value: - namespace App\Providers; +public function getIsAdminAttribute() +{ +return $this->attributes['admin'] == 'yes'; +} - use App\User; - use Illuminate\Support\ServiceProvider; +Once you have created the accessor, just add the value to the `appends` property on the model: - class AppServiceProvider extends ServiceProvider - { - /** - * Bootstrap any application services. - * - * @return void - */ - public function boot() - { - User::creating(function ($user) { - return $user->isValid(); - }); - } +protected $appends = array('is_admin'); - /** - * Register the service provider. - * - * @return void - */ - public function register() - { - // - } - } +Once the attribute has been added to the `appends` list, it will be included in both the model's array and JSON forms. \ No newline at end of file diff --git a/encryption.md b/encryption.md deleted file mode 100644 index a0a9130..0000000 --- a/encryption.md +++ /dev/null @@ -1,63 +0,0 @@ -# Encryption - -- [Introduction](#introduction) -- [Configuration](#configuration) -- [Using The Encrypter](#using-the-encrypter) - - -## Introduction - -Laravel's encrypter uses OpenSSL to provide AES-256 and AES-128 encryption. You are strongly encouraged to use Laravel's built-in encryption facilities and not attempt to roll your own "home grown" encryption algorithms. All of Laravel's encrypted values are signed using a message authentication code (MAC) so that their underlying value can not be modified once encrypted. - - -## Configuration - -Before using Laravel's encrypter, you must set a `key` option in your `config/app.php` configuration file. You should use the `php artisan key:generate` command to generate this key since this Artisan command will use PHP's secure random bytes generator to build your key. If this value is not properly set, all values encrypted by Laravel will be insecure. - - -## Using The Encrypter - -#### Encrypting A Value - -You may encrypt a value using the `encrypt` helper. All encrypted values are encrypted using OpenSSL and the `AES-256-CBC` cipher. Furthermore, all encrypted values are signed with a message authentication code (MAC) to detect any modifications to the encrypted string: - - fill([ - 'secret' => encrypt($request->secret) - ])->save(); - } - } - -> {note} Encrypted values are passed through `serialize` during encryption, which allows for encryption of objects and arrays. Thus, non-PHP clients receiving encrypted values will need to `unserialize` the data. - -#### Decrypting A Value - -You may decrypt values using the `decrypt` helper. If the value can not be properly decrypted, such as when the MAC is invalid, an `Illuminate\Contracts\Encryption\DecryptException` will be thrown: - - use Illuminate\Contracts\Encryption\DecryptException; - - try { - $decrypted = decrypt($encryptedValue); - } catch (DecryptException $e) { - // - } diff --git a/envoy.md b/envoy.md deleted file mode 100644 index 783ef30..0000000 --- a/envoy.md +++ /dev/null @@ -1,180 +0,0 @@ -# Envoy Task Runner - -- [Introduction](#introduction) - - [Installation](#installation) -- [Writing Tasks](#writing-tasks) - - [Setup](#setup) - - [Variables](#variables) - - [Stories](#stories) - - [Multiple Servers](#multiple-servers) -- [Running Tasks](#running-tasks) - - [Confirming Task Execution](#confirming-task-execution) -- [Notifications](#notifications) - - [Slack](#slack) - - -## Introduction - -[Laravel Envoy](https://github.com/laravel/envoy) provides a clean, minimal syntax for defining common tasks you run on your remote servers. Using Blade style syntax, you can easily setup tasks for deployment, Artisan commands, and more. Currently, Envoy only supports the Mac and Linux operating systems. - - -### Installation - -First, install Envoy using the Composer `global require` command: - - composer global require "laravel/envoy=~1.0" - -Since global Composer libraries can sometimes cause package version conflicts, you may wish to consider using `cgr`, which is a drop-in replacement for the `composer global require` command. The `cgr` library's installation instructions can be [found on GitHub](https://github.com/consolidation-org/cgr). - -> {note} Make sure to place the `~/.composer/vendor/bin` directory in your PATH so the `envoy` executable is found when running the `envoy` command in your terminal. - -#### Updating Envoy - -You may also use Composer to keep your Envoy installation up to date. Issuing the the `composer global update` command will update all of your globally installed Composer packages: - - composer global update - - -## Writing Tasks - -All of your Envoy tasks should be defined in an `Envoy.blade.php` file in the root of your project. Here's an example to get you started: - - @servers(['web' => ['user@192.168.1.1']]) - - @task('foo', ['on' => 'web']) - ls -la - @endtask - -As you can see, an array of `@servers` is defined at the top of the file, allowing you to reference these servers in the `on` option of your task declarations. Within your `@task` declarations, you should place the Bash code that should run on your server when the task is executed. - -You can force a script to run locally by specifying the server's IP address as `127.0.0.1`: - - @servers(['localhost' => '127.0.0.1']) - - -### Setup - -Sometimes, you may need to execute some PHP code before executing your Envoy tasks. You may use the ```@setup``` directive to declare variables and do other general PHP work before any of your other tasks are executed: - - @setup - $now = new DateTime(); - - $environment = isset($env) ? $env : "testing"; - @endsetup - -If you need to require other PHP files before your task is executed, you may use the `@include` directive at the top of your `Envoy.blade.php` file: - - @include('vendor/autoload.php') - - @task('foo') - # ... - @endtask - - -### Variables - -If needed, you may pass option values into Envoy tasks using the command line: - - envoy run deploy --branch=master - -You may use access the options in your tasks via Blade's "echo" syntax. Of course, you may also use `if` statements and loops within your tasks. For example, let's verify the presence of the `$branch` variable before executing the `git pull` command: - - @servers(['web' => '192.168.1.1']) - - @task('deploy', ['on' => 'web']) - cd site - - @if ($branch) - git pull origin {{ $branch }} - @endif - - php artisan migrate - @endtask - - -### Stories - -Stories group a set of tasks under a single, convenient name, allowing you to group small, focused tasks into large tasks. For instance, a `deploy` story may run the `git` and `composer` tasks by listing the task names within its definition: - - @servers(['web' => '192.168.1.1']) - - @story('deploy') - git - composer - @endstory - - @task('git') - git pull origin master - @endtask - - @task('composer') - composer install - @endtask - -Once the story has been written, you may run it just like a typical task: - - envoy run deploy - - -### Multiple Servers - -Envoy allows you to easily run a task across multiple servers. First, add additional servers to your `@servers` declaration. Each server should be assigned a unique name. Once you have defined your additional servers, list each of the servers in the task's `on` array: - - @servers(['web-1' => '192.168.1.1', 'web-2' => '192.168.1.2']) - - @task('deploy', ['on' => ['web-1', 'web-2']]) - cd site - git pull origin {{ $branch }} - php artisan migrate - @endtask - -#### Parallel Execution - -By default, tasks will be executed on each server serially. In other words, a task will finish running on the first server before proceeding to execute on the second server. If you would like to run a task across multiple servers in parallel, add the `parallel` option to your task declaration: - - @servers(['web-1' => '192.168.1.1', 'web-2' => '192.168.1.2']) - - @task('deploy', ['on' => ['web-1', 'web-2'], 'parallel' => true]) - cd site - git pull origin {{ $branch }} - php artisan migrate - @endtask - - -## Running Tasks - -To run a task or story that is defined in your `Envoy.blade.php` file, execute Envoy's `run` command, passing the name of the task or story you would like to execute. Envoy will run the task and display the output from the servers as the task is running: - - envoy run task - - -### Confirming Task Execution - -If you would like to be prompted for confirmation before running a given task on your servers, you should add the `confirm` directive to your task declaration. This option is particularly useful for destructive operations: - - @task('deploy', ['on' => 'web', 'confirm' => true]) - cd site - git pull origin {{ $branch }} - php artisan migrate - @endtask - - - -## Notifications - - -### Slack - -Envoy also supports sending notifications to [Slack](https://slack.com) after each task is executed. The `@slack` directive accepts a Slack hook URL and a channel name. You may retrieve your webhook URL by creating an "Incoming WebHooks" integration in your Slack control panel. You should pass the entire webhook URL into the `@slack` directive: - - @after - @slack('webhook-url', '#bots') - @endafter - -You may provide one of the following as the channel argument: - -
    -- To send the notification to a channel: `#channel` -- To send the notification to a user: `@user` -
    - diff --git a/errors.md b/errors.md index d099173..d713445 100644 --- a/errors.md +++ b/errors.md @@ -1,199 +1,117 @@ # Errors & Logging -- [Introduction](#introduction) - [Configuration](#configuration) - - [Error Detail](#error-detail) - - [Log Storage](#log-storage) - - [Log Severity Levels](#log-severity-levels) - - [Custom Monolog Configuration](#custom-monolog-configuration) -- [The Exception Handler](#the-exception-handler) - - [Report Method](#report-method) - - [Render Method](#render-method) +- [Error တွေကို ထိန်းချုပ်ခြင်း](#handling-errors) - [HTTP Exceptions](#http-exceptions) - - [Custom HTTP Error Pages](#custom-http-error-pages) +- [404 Errors များကို ထိန်းချုပ်ခြင်း](#handling-404-errors) - [Logging](#logging) - -## Introduction - -When you start a new Laravel project, error and exception handling is already configured for you. The `App\Exceptions\Handler` class is where all exceptions triggered by your application are logged and then rendered back to the user. We'll dive deeper into this class throughout this documentation. - -For logging, Laravel utilizes the [Monolog](https://github.com/Seldaek/monolog) library, which provides support for a variety of powerful log handlers. Laravel configures several of these handlers for you, allowing you to choose between a single log file, rotating log files, or writing error information to the system log. - ## Configuration - -### Error Detail - -The `debug` option in your `config/app.php` configuration file determines how much information about an error is actually displayed to the user. By default, this option is set to respect the value of the `APP_DEBUG` environment variable, which is stored in your `.env` file. - -For local development, you should set the `APP_DEBUG` environment variable to `true`. In your production environment, this value should always be `false`. If the value is set to `true` in production, you risk exposing sensitive configuration values to your application's end users. - - -### Log Storage - -Out of the box, Laravel supports writing log information to `single` files, `daily` files, the `syslog`, and the `errorlog`. To configure which storage mechanism Laravel uses, you should modify the `log` option in your `config/app.php` configuration file. For example, if you wish to use daily log files instead of a single file, you should set the `log` value in your `app` configuration file to `daily`: - - 'log' => 'daily' - -#### Maximum Daily Log Files +Application ရဲ့ Logging Handler ကို `app/start/global.php` [start file](lifecycle#start-files) ထဲမှာ Registered လုပ်ထားပါတယ်။ နဂိုအတိုင်းကတော့ File တစ်ဖိုင်ထဲကိုပဲ အသုံးပြုခိုင်းထားပါတယ်။ သို့သော်လည်း သင့်စိတ်ကြိုက် ပြင်ဆင်နိုင်ပါတယ်။ Laravel က နာမည်ကြီး Loggin Library တစ်ခုဖြစ်တဲ့ [Monolog](https://github.com/Seldaek/monolog.md) ကိုသုံးထားတဲ့အတွက် Monolog မှာပါဝင်တဲ့ အမျိုးအမျိုးသော handler များကိုအသုံးပြုနိုင်ပါတယ်။ -When using the `daily` log mode, Laravel will only retain five days of log files by default. If you want to adjust the number of retained files, you may add a `log_max_files` configuration value to your `app` configuration file: +ဥပမာ - Log File တစ်ခုတည်းမထားဘဲ နေ့စဉ်အလိုက် Log file တွေခွဲထားချင်တယ်ဆိုရင် ၊ start file မှာအောက်ကအတိုင်း ပြောင်းရေးလိုက်လို့ရပါတယ် - 'log_max_files' => 30 + $logFile = 'laravel.log'; - -### Log Severity Levels + Log::useDailyFiles(storage_path().'/logs/'.$logFile); -When using Monolog, log messages may have different levels of severity. By default, Laravel writes all log levels to storage. However, in your production environment, you may wish to configure the minimum severity that should be logged by adding the `log_level` option to your `app.php` configuration file. +### Error အသေးစိတ် -Once this option has been configured, Laravel will log all levels greater than or equal to the specified severity. For example, a default `log_level` of `error` will log **error**, **critical**, **alert**, and **emergency** messages: +အရင်အတိုင်းဆို ၊ Error ရဲ့အသေးစိတ်ကို ဖော်ပြပါလိမ့်မယ်။ ဆိုလိုတာက Application မှာ Error တစ်ခုတက်နေမယ်ဆိုရင် ၊ အဲဒီ Error ရဲ့အသေးစိတ်နဲ့ ၊ အဲဒီ Error နဲ့ပတ်သက်နေတဲ့ ဖိုင်တွေနဲ့ အသေးစိတ်အချက်အလက်တွေကို ဖော်ပြပေးပါလိမ့်မယ်။ ဒီ Error အသေးစိတ်ပြတဲ့ Feature ကို ပိတ်ချင်တယ်ဆိုရင်တော့ `app/config/app.php` ထဲမှာ `debug` option ကို `false` လို့ လုပ်ပေးလိုက်ရုံပါပဲ။ - 'log_level' => env('APP_LOG_LEVEL', 'error'), +> **မှတ်ချက်:** Application တကယ် Run ပြီဆိုရင်တော့ ဒီ Feature ကို ပိတ်ထားဖို့အတွက် အကြံပြုချင်ပါတယ်။ -> {tip} Monolog recognizes the following severity levels - from least severe to most severe: `debug`, `info`, `notice`, `warning`, `error`, `critical`, `alert`, `emergency`. + +## Error တွေကို ထိန်းချုပ်ခြင်း - -### Custom Monolog Configuration +Default အနေနဲ့က `app/start/global.php` ထဲမှာ Exception တွေတိုင်းအတွက် Error Handler တစ်ခုပါရှိပါတယ်။ -If you would like to have complete control over how Monolog is configured for your application, you may use the application's `configureMonologUsing` method. You should place a call to this method in your `bootstrap/app.php` file right before the `$app` variable is returned by the file: + App::error(function(Exception $exception) + { + Log::error($exception); + }); - $app->configureMonologUsing(function($monolog) { - $monolog->pushHandler(...); - }); +ဒါကတော့ အရမ်းရိုးရှင်းတဲ့ Error Handler တစ်ခုပဲဖြစ်ပါတယ်။ တကယ်လို့ လိုအပ်မယ်ဆိုရင်တော့ ရှုပ်ထွေးတဲ့ Handler တွေကို သတ်မှတ်ပေးနိုင်ပါတယ်။ Exception တွေရဲ့နာမည်ပေါ်မူတည်ပြီး Handler တွေကိုခေါ်ပါတယ်။ ဥပမာပေးရမယ်ဆိုရင် ၊ `RunetimeException` အတွက်ပဲ handle လုပ်တဲ့ handler ကို အောက်ကအတိုင်း ရေးရပါမယ်။ - return $app; + App::error(function(RuntimeException $exception) + { + // Handle the exception... + }); - -## The Exception Handler +Exception Handler တစ်ခုက Response တစ်ခု Return ပြန်မယ်ဆိုရင် အဲဒီ Response ကိုပဲ Browser မှာဖော်ပြမှာဖြစ်ပြီး ၊ တစ်ခြားသော Error Handler တွေကိုခေါ်မှာမဟုတ်ပါဘူး - -### The Report Method + App::error(function(InvalidUserException $exception) + { + Log::error($exception); -All exceptions are handled by the `App\Exceptions\Handler` class. This class contains two methods: `report` and `render`. We'll examine each of these methods in detail. The `report` method is used to log exceptions or send them to an external service like [BugSnag](https://bugsnag.com) or [Sentry](https://github.com/getsentry/sentry-laravel). By default, the `report` method simply passes the exception to the base class where the exception is logged. However, you are free to log exceptions however you wish. + return 'Sorry! Something is wrong with this account!'; + }); -For example, if you need to report different types of exceptions in different ways, you may use the PHP `instanceof` comparison operator: +PHP fatal error ဖြစ်တဲ့အချိန်ကို စောင့်ဖမ်းချင်ရင်တော့ `App::fatal` method ကိုသုံးရပါမယ် - /** - * Report or log an exception. - * - * This is a great spot to send exceptions to Sentry, Bugsnag, etc. - * - * @param \Exception $e - * @return void - */ - public function report(Exception $e) - { - if ($e instanceof CustomException) { - // - } + App::fatal(function($exception) + { + // + }); - return parent::report($e); - } +Handler တွေအများကြီးရှိတယ်ဆိုရင်တော့ General ကြတဲ့ Handler တွေမှ အသေးစိတ်ကျတဲ့ handler တွေအထိအစဉ်လိုက် သတ်မှတ်ပေးသင့်ပါတယ်။ ဥပမာ - `Exception` တွေအားလုံးကို handler လုပ်တဲ့ handler တွေကိုအရင်ဆုံး သတ်မှတ်ပါ၊ ပြီးမှ `Illuminate\Encryption\DecryptException` လိုမျိုး အသေးစိတ် exception ကိုတော့ နောက်မှသတ်မှတ်ပေးပါ။ -#### Ignoring Exceptions By Type +### Error Handlers တွေကို ဘယ်မှာရေးရမလဲ -The `$dontReport` property of the exception handler contains an array of exception types that will not be logged. For example, exceptions resulting from 404 errors, as well as several other types of errors, are not written to your log files. You may add other exception types to this array as needed: - - /** - * A list of the exception types that should not be reported. - * - * @var array - */ - protected $dontReport = [ - \Illuminate\Auth\AuthenticationException::class, - \Illuminate\Auth\Access\AuthorizationException::class, - \Symfony\Component\HttpKernel\Exception\HttpException::class, - \Illuminate\Database\Eloquent\ModelNotFoundException::class, - \Illuminate\Validation\ValidationException::class, - ]; - - -### The Render Method - -The `render` method is responsible for converting a given exception into an HTTP response that should be sent back to the browser. By default, the exception is passed to the base class which generates a response for you. However, you are free to check the exception type or return your own custom response: - - /** - * Render an exception into an HTTP response. - * - * @param \Illuminate\Http\Request $request - * @param \Exception $e - * @return \Illuminate\Http\Response - */ - public function render($request, Exception $e) - { - if ($e instanceof CustomException) { - return response()->view('errors.custom', [], 500); - } - - return parent::render($request, $e); - } +Error Handler တွေကို သတ်မှတ်ပေးရမယ့် နေရာဆိုပြီးမသတ်မှတ်ထားပါဘူး။ ဒါနဲ့ပတ်သက်ပြီးလို့ကတော့ Laravel က လွတ်လပ်ခွင့်ပေးထားပါတယ်။ နည်းလမ်းတစ်ခုကတော့ `start/global.php` ထဲမှာ ထည့်ရေးနိုင်ပါတယ်။ အဲဒီနေရာက Application စစ Run ချင်း Code တွေထည့်ရေးသင့်တဲ့ အကောင်းဆုံးနေရာပါဘဲ။ အဲဒီဖိုင်ထဲမှာ တစ်ခြားရေးထားတာတွေ များနေတယ်ဆိုရင်တော့ `app/errors.php` ဆိုပြီး ဖိုင်ဆောက်လိုက်ပြီးတော့ `start/global.php` ထဲမှာ `require` လုပ်ပြီးရေးလို့ရပါတယ်။ တတိယနည်းလမ်းကတော့ Handler တွေအားလုံးကို ထိန်းချုပ်ပေးမယ့် [service provider](ioc#service-providers.md) တစ်ခု ဖန်းတီးလိုက်ပါ။ နောက်ထပ်တစ်ခေါက်ထပ်ပြောချင်ပါတယ် ၊ အဖြေမှန်ဆိုပြီးရယ်လို့ မရှိပါဘူး။ သင်နဲ့အကိုက်ညီဆုံးပုံစံအသုံးပြုပါ။ ## HTTP Exceptions -Some exceptions describe HTTP error codes from the server. For example, this may be a "page not found" error (404), an "unauthorized error" (401) or even a developer generated 500 error. In order to generate such a response from anywhere in your application, you may use the `abort` helper: +အချို့ Exception တွေက Server ကနေပြီးတော့ HTTP error code တွေဖော်ပြပေးပါတယ်။ ဥပမာ - "page not found" error (404), "unauthorized error" (401) သို့မဟုတ် 500 error လိုမျိုးဖြစ်ပါတယ်။ ဒီလို Response အတွက်တွေဆို အောက်ကအတိုင်းသုံးပါ။ + + App::abort(404); - abort(404); +ကိုယ်ပိုင် message နဲ့ response လုပ်ပေးချင်လဲရပါတယ်။ -The `abort` helper will immediately raise an exception which will be rendered by the exception handler. Optionally, you may provide the response text: + App::abort(403, 'Unauthorized action.'); - abort(403, 'Unauthorized action.'); +အဲဒီ method ကို Application တစ်ခုလုံးရဲ့ request တွေအားလုံးမှာ အသုံးပြုမှာပါ။ - -### Custom HTTP Error Pages + +## 404 Errors များကို ထိန်းချုပ်ခြင်း -Laravel makes it easy to display custom error pages for various HTTP status codes. For example, if you wish to customize the error page for 404 HTTP status codes, create a `resources/views/errors/404.blade.php`. This file will be served on all 404 errors generated by your application. The views within this directory should be named to match the HTTP status code they correspond to. The `HttpException` instance raised by the `abort` function will be passed to the view as an `$exception` variable. +"404 Not Found" error တွေအားလုံးကို ထိန်းချုပ်ပေးမယ့် handler ကိုလဲ ကိုယ့်စိတ်ကြိုက်ပုံစံနဲ့ အလွယ်တကူသတ်မှတ်ပေးနိုင်ပါတယ်။ + + App::missing(function($exception) + { + return Response::view('errors.missing', array(), 404); + }); ## Logging -Laravel provides a simple abstraction layer on top of the powerful [Monolog](http://github.com/seldaek/monolog) library. By default, Laravel is configured to create a log file for your application in the `storage/logs` directory. You may write information to the logs using the `Log` [facade](/docs/{{version}}/facades): - - User::findOrFail($id)]); - } - } +Logger အနေနဲ့ [RFC 5424](http://tools.ietf.org/html/rfc5424) ကသတ်မှတ်ပေးထားတဲ့အတိုင်း **debug**, **info**, **notice**, **warning**, **error**, **critical**, and **alert** ဆိုပြီး level ၇ ခုရှိပါတယ်။ -The logger provides the eight logging levels defined in [RFC 5424](http://tools.ietf.org/html/rfc5424): **emergency**, **alert**, **critical**, **error**, **warning**, **notice**, **info** and **debug**. - Log::emergency($message); - Log::alert($message); - Log::critical($message); - Log::error($message); - Log::warning($message); - Log::notice($message); - Log::info($message); - Log::debug($message); +Array ပုံစံနဲ့လည်း ထည့်ပေးလိုက်လို့ရပါတယ် -#### Contextual Information + Log::info('Log message', array('context' => 'Other helpful information')); -An array of contextual data may also be passed to the log methods. This contextual data will be formatted and displayed with the log message: +Monolog မှာ တစ်ခြား handler တွေ အများကြီးပါဝင်ပါတယ်။ လိုအပ်ရင် Laravel သုံးထားတဲံ Monolog instance ကိုသုံးနိုင်ပါတယ်။ - Log::info('User failed to login.', ['id' => $user->id]); + $monolog = Log::getMonolog(); -#### Accessing The Underlying Monolog Instance +Log ဖိုင်ထဲကို ထည့်သမျှ message တွေအားလုံးကို စောင့်ဖမ်းဖို့အတွက်လဲ event ရေးထားလို့ရပါတယ်။ -Monolog has a variety of additional handlers you may use for logging. If needed, you may access the underlying Monolog instance being used by Laravel: +#### Registering A Log Listener - $monolog = Log::getMonolog(); + Log::listen(function($level, $message, $context) + { + // + }); diff --git a/events.md b/events.md index de1f882..21ed090 100644 --- a/events.md +++ b/events.md @@ -1,273 +1,175 @@ # Events -- [Introduction](#introduction) -- [Registering Events & Listeners](#registering-events-and-listeners) - - [Generating Events & Listeners](#generating-events-and-listeners) - - [Manually Registering Events](#manually-registering-events) -- [Defining Events](#defining-events) -- [Defining Listeners](#defining-listeners) -- [Queued Event Listeners](#queued-event-listeners) - - [Manually Accessing The Queue](#manually-accessing-the-queue) -- [Firing Events](#firing-events) +- [Basic Usage](#basic-usage) +- [Wildcard Listeners](#wildcard-listeners) +- [Using Classes As Listeners](#using-classes-as-listeners) +- [Queued Events](#queued-events) - [Event Subscribers](#event-subscribers) - - [Writing Event Subscribers](#writing-event-subscribers) - - [Registering Event Subscribers](#registering-event-subscribers) - -## Introduction + +## Basic Usage -Laravel's events provides a simple observer implementation, allowing you to subscribe and listen for various events that occur in your application. Event classes are typically stored in the `app/Events` directory, while their listeners are stored in `app/Listeners`. Don't worry if you don't see these directories in your application, since they will be created for you as you generate events and listeners using Artisan console commands. +The Laravel `Event` class provides a simple observer implementation, allowing you to subscribe and listen for events in your application. -Events serve as a great way to decouple various aspects of your application, since a single event can have multiple listeners that do not depend on each other. For example, you may wish to send a Slack notification to your user each time an order has shipped. Instead of coupling your order processing code to your Slack notification code, you can simply raise an `OrderShipped` event, which a listener can receive and transform into a Slack notification. +#### Subscribing To An Event - -## Registering Events & Listeners + Event::listen('auth.login', function($user) + { + $user->last_login = new DateTime; -The `EventServiceProvider` included with your Laravel application provides a convenient place to register all of your application's event listeners. The `listen` property contains an array of all events (keys) and their listeners (values). Of course, you may add as many events to this array as your application requires. For example, let's add a `OrderShipped` event: + $user->save(); + }); - /** - * The event listener mappings for the application. - * - * @var array - */ - protected $listen = [ - 'App\Events\OrderShipped' => [ - 'App\Listeners\SendShipmentNotification', - ], - ]; +#### Firing An Event - -### Generating Events & Listeners + $event = Event::fire('auth.login', array($user)); -Of course, manually creating the files for each event and listener is cumbersome. Instead, simply add listeners and events to your `EventServiceProvider` and use the `event:generate` command. This command will generate any events or listeners that are listed in your `EventServiceProvider`. Of course, events and listeners that already exist will be left untouched: +#### Subscribing To Events With Priority - php artisan event:generate +You may also specify a priority when subscribing to events. Listeners with higher priority will be run first, while listeners that have the same priority will be run in order of subscription. - -## Defining Events + Event::listen('auth.login', 'LoginHandler', 10); -An event class is simply a data container which holds the information related to the event. For example, let's assume our generated `OrderShipped` event receives an [Eloquent ORM](/docs/{{version}}/eloquent) object: + Event::listen('auth.login', 'OtherHandler', 5); - order = $order; - } - } +So, you know how to register events, but you may be wondering _where_ to register them. Don't worry, this is a common question. Unfortunately, it's a hard question to answer because you can register an event almost anywhere! But, here are some tips. Again, like most other bootstrapping code, you may register events in one of your `start` files such as `app/start/global.php`. -As you can see, this event class contains no logic. It is simply a container for the `Order` instance that was purchased. The `SerializesModels` trait used by the event will gracefully serialize any Eloquent models if the event object is serialized using PHP's `serialize` function. +If your `start` files are getting too crowded, you could create a separate `app/events.php` file that is included from a `start` file. This is a simple solution that keeps your event registration cleanly separated from the rest of your bootstrapping. If you prefer a class based approach, you may register your events in a [service provider](ioc#service-providers.md). Since none of these approaches is inherently "correct", choose an approach you feel comfortable with based on the size of your application. - -## Defining Listeners + +## Wildcard Listeners -Next, let's take a look at the listener for our example event. Event listeners receive the event instance in their `handle` method. The `event:generate` command will automatically import the proper event class and type-hint the event on the `handle` method. Within the `handle` method, you may perform any actions necessary to respond to the event: +#### Registering Wildcard Event Listeners - order... - } - } + Event::listen('foo.*', function($param) + { + if (Event::firing() == 'foo.bar') + { + // + } + }); -> {tip} Your event listeners may also type-hint any dependencies they need on their constructors. All event listeners are resolved via the Laravel [service container](/docs/{{version}}/container), so dependencies will be injected automatically. + +## Using Classes As Listeners -#### Stopping The Propagation Of An Event +In some cases, you may wish to use a class to handle an event rather than a Closure. Class event listeners will be resolved out of the [Laravel IoC container](ioc.md), providing you the full power of dependency injection on your listeners. -Sometimes, you may wish to stop the propagation of an event to other listeners. You may do so by returning `false` from your listener's `handle` method. +#### Registering A Class Listener - -## Queued Event Listeners + Event::listen('auth.login', 'LoginHandler'); -Queueing listeners can be beneficial if your listener is going to perform a slow task such as sending an e-mail or making an HTTP request. Before getting started with queued listeners, make sure to [configure your queue](/docs/{{version}}/queues) and start a queue listener on your server or local development environment. +#### Defining An Event Listener Class -To specify that a listener should be queued, add the `ShouldQueue` interface to the listener class. Listeners generated by the `event:generate` Artisan command already have this interface imported into the current namespace, so you can use it immediately: +By default, the `handle` method on the `LoginHandler` class will be called: - -### Manually Accessing The Queue + Event::listen('auth.login', 'LoginHandler@onLogin'); -If you need to manually access the listener's underlying queue job's `delete` and `release` methods, you may do so using the `Illuminate\Queue\InteractsWithQueue` trait. This trait is imported by default on generated listeners and provides access to these methods: + +## Queued Events - release(30); - } - } - } + Event::flusher('foo', function($user) + { + // + }); - -## Firing Events +Finally, you may run the "flusher" and flush all queued events using the `flush` method: -To fire an event, you may pass an instance of the event to the `event` helper. The helper will dispatch the event to all of its registered listeners. Since the `event` helper is globally available, you may call it from anywhere in your application: + Event::flush('foo'); - +## Event Subscribers - namespace App\Http\Controllers; +#### Defining An Event Subscriber - use App\Order; - use App\Events\OrderShipped; - use App\Http\Controllers\Controller; +Event subscribers are classes that may subscribe to multiple events from within the class itself. Subscribers should define a `subscribe` method, which will be passed an event dispatcher instance: - class OrderController extends Controller - { - /** - * Ship the given order. - * - * @param int $orderId - * @return Response - */ - public function ship($orderId) - { - $order = Order::findOrFail($orderId); + class UserEventHandler { - // Order shipment logic... + /** + * Handle user login events. + */ + public function onUserLogin($event) + { + // + } - event(new OrderShipped($order)); - } - } + /** + * Handle user logout events. + */ + public function onUserLogout($event) + { + // + } -> {tip} When testing, it can be helpful to assert that certain events were fired without actually triggering their listeners. Laravel's [built-in testing helpers](/docs/{{version}}/mocking#mocking-events) makes it a cinch. + /** + * Register the listeners for the subscriber. + * + * @param Illuminate\Events\Dispatcher $events + * @return array + */ + public function subscribe($events) + { + $events->listen('auth.login', 'UserEventHandler@onUserLogin'); - -## Event Subscribers + $events->listen('auth.logout', 'UserEventHandler@onUserLogout'); + } + + } + +#### Registering An Event Subscriber + +Once the subscriber has been defined, it may be registered with the `Event` class. + + $subscriber = new UserEventHandler; + + Event::subscribe($subscriber); + +You may also use the [Laravel IoC container](ioc.md) to resolve your subscriber. To do so, simply pass the name of your subscriber to the `subscribe` method: + + Event::subscribe('UserEventHandler'); - -### Writing Event Subscribers - -Event subscribers are classes that may subscribe to multiple events from within the class itself, allowing you to define several event handlers within a single class. Subscribers should define a `subscribe` method, which will be passed an event dispatcher instance. You may call the `listen` method on the given dispatcher to register event listeners: - - listen( - 'Illuminate\Auth\Events\Login', - 'App\Listeners\UserEventSubscriber@onUserLogin' - ); - - $events->listen( - 'Illuminate\Auth\Events\Logout', - 'App\Listeners\UserEventSubscriber@onUserLogout' - ); - } - - } - - -### Registering Event Subscribers - -After writing the subscriber, you are ready to register it with the event dispatcher. You may register subscribers using the `$subscribe` property on the `EventServiceProvider`. For example, let's add the `UserEventSubscriber` to the list: - - +## Introduction + +Laravel offers many extension points for you to customize the behavior of the framework's core components, or even replace them entirely. For example, the hashing facilities are defined by a `HasherInterface` contract, which you may implement based on your application's requirements. You may also extend the `Request` object, allowing you to add your own convenient "helper" methods. You may even add entirely new authentication, cache, and session drivers! + +Laravel components are generally extended in two ways: binding new implementations in the IoC container, or registering an extension with a `Manager` class, which are implementations of the "Factory" design pattern. In this chapter we'll explore the various methods of extending the framework and examine the necessary code. + +> **Note:** Remember, Laravel components are typically extended in one of two ways: IoC bindings and the `Manager` classes. The manager classes serve as an implementation of the "factory" design pattern, and are responsible for instantiating driver based facilities such as cache and session. + + +## Managers & Factories + +Laravel has several `Manager` classes that manage the creation of driver-based components. These include the cache, session, authentication, and queue components. The manager class is responsible for creating a particular driver implementation based on the application's configuration. For example, the `CacheManager` class can create APC, Memcached, File, and various other implementations of cache drivers. + +Each of these managers includes an `extend` method which may be used to easily inject new driver resolution functionality into the manager. We'll cover each of these managers below, with examples of how to inject custom driver support into each of them. + +> **Note:** Take a moment to explore the various `Manager` classes that ship with Laravel, such as the `CacheManager` and `SessionManager`. Reading through these classes will give you a more thorough understanding of how Laravel works under the hood. All manager classes extend the `Illuminate\Support\Manager` base class, which provides some helpful, common functionality for each manager. + + +## Where To Extend + +This documentation covers how to extend a variety of Laravel's components, but you may be wondering where to place your extension code. Like most other bootstrapping code, you are free to place some extensions in your `start` files. Cache and Auth extensions are good candidates for this approach. Other extensions, like `Session`, must be placed in the `register` method of a service provider since they are needed very early in the request life-cycle. + + +## Cache + +To extend the Laravel cache facility, we will use the `extend` method on the `CacheManager`, which is used to bind a custom driver resolver to the manager, and is common across all manager classes. For example, to register a new cache driver named "mongo", we would do the following: + + Cache::extend('mongo', function($app) + { + // Return Illuminate\Cache\Repository instance... + }); + +The first argument passed to the `extend` method is the name of the driver. This will correspond to your `driver` option in the `app/config/cache.php` configuration file. The second argument is a Closure that should return an `Illuminate\Cache\Repository` instance. The Closure will be passed an `$app` instance, which is an instance of `Illuminate\Foundation\Application` and an IoC container. + +To create our custom cache driver, we first need to implement the `Illuminate\Cache\StoreInterface` contract. So, our MongoDB cache implementation would look something like this: + + class MongoStore implements Illuminate\Cache\StoreInterface { + + public function get($key) {} + public function put($key, $value, $minutes) {} + public function increment($key, $value = 1) {} + public function decrement($key, $value = 1) {} + public function forever($key, $value) {} + public function forget($key) {} + public function flush() {} + + } + +We just need to implement each of these methods using a MongoDB connection. Once our implementation is complete, we can finish our custom driver registration: + + use Illuminate\Cache\Repository; + + Cache::extend('mongo', function($app) + { + return new Repository(new MongoStore); + }); + +As you can see in the example above, you may use the base `Illuminate\Cache\Repository` when creating custom cache drivers. There is typically no need to create your own repository class. + +If you're wondering where to put your custom cache driver code, consider making it available on Packagist! Or, you could create an `Extensions` namespace within your application's primary folder. For example, if the application is named `Snappy`, you could place the cache extension in `app/Snappy/Extensions/MongoStore.php`. However, keep in mind that Laravel does not have a rigid application structure and you are free to organize your application according to your preferences. + +> **Note:** If you're ever wondering where to put a piece of code, always consider a service provider. As we've discussed, using a service provider to organize framework extensions is a great way to organize your code. + + +## Session + +Extending Laravel with a custom session driver is just as easy as extending the cache system. Again, we will use the `extend` method to register our custom code: + + Session::extend('mongo', function($app) + { + // Return implementation of SessionHandlerInterface + }); + +### Where To Extend The Session + +Session extensions need to be registered differently than other extensions like Cache and Auth. Since sessions are started very early in the request-lifecycle, registering the extensions in a `start` file will happen be too late. Instead, a [service provider](ioc#service-providers.md) will be needed. You should place your session extension code in the `register` method of your service provider, and the provider should be placed **below** the default `Illuminate\Session\SessionServiceProvider` in the `providers` configuration array. + +### Writing The Session Extension + +Note that our custom cache driver should implement the `SessionHandlerInterface`. This interface is included in the PHP 5.4+ core. If you are using PHP 5.3, the interface will be defined for you by Laravel so you have forward-compatibility. This interface contains just a few simple methods we need to implement. A stubbed MongoDB implementation would look something like this: + + class MongoHandler implements SessionHandlerInterface { + + public function open($savePath, $sessionName) {} + public function close() {} + public function read($sessionId) {} + public function write($sessionId, $data) {} + public function destroy($sessionId) {} + public function gc($lifetime) {} + + } + +Since these methods are not as readily understandable as the cache `StoreInterface`, let's quickly cover what each of the methods do: + +- The `open` method would typically be used in file based session store systems. Since Laravel ships with a `file` session driver, you will almost never need to put anything in this method. You can leave it as an empty stub. It is simply a fact of poor interface design (which we'll discuss later) that PHP requires us to implement this method. +- The `close` method, like the `open` method, can also usually be disregarded. For most drivers, it is not needed. +- The `read` method should return the string version of the session data associated with the given `$sessionId`. There is no need to do any serialization or other encoding when retrieving or storing session data in your driver, as Laravel will perform the serialization for you. +- The `write` method should write the given `$data` string associated with the `$sessionId` to some persistent storage system, such as MongoDB, Dynamo, etc. +- The `destroy` method should remove the data associated with the `$sessionId` from persistent storage. +- The `gc` method should destroy all session data that is older than the given `$lifetime`, which is a UNIX timestamp. For self-expiring systems like Memcached and Redis, this method may be left empty. + +Once the `SessionHandlerInterface` has been implemented, we are ready to register it with the Session manager: + + Session::extend('mongo', function($app) + { + return new MongoHandler; + }); + +Once the session driver has been registered, we may use the `mongo` driver in our `app/config/session.php` configuration file. + +> **Note:** Remember, if you write a custom session handler, share it on Packagist! + + +## Authentication + +Authentication may be extended the same way as the cache and session facilities. Again, we will use the `extend` method we have become familiar with: + + Auth::extend('riak', function($app) + { + // Return implementation of Illuminate\Auth\UserProviderInterface + }); + +The `UserProviderInterface` implementations are only responsible for fetching a `UserInterface` implementation out of a persistent storage system, such as MySQL, Riak, etc. These two interfaces allow the Laravel authentication mechanisms to continue functioning regardless of how the user data is stored or what type of class is used to represent it. + +Let's take a look at the `UserProviderInterface`: + + interface UserProviderInterface { + + public function retrieveById($identifier); + public function retrieveByCredentials(array $credentials); + public function validateCredentials(UserInterface $user, array $credentials); + + } + +The `retrieveById` function typically receives a numeric key representing the user, such as an auto-incrementing ID from a MySQL database. The `UserInterface` implementation matching the ID should be retrieved and returned by the method. + +The `retrieveByCredentials` method receives the array of credentials passed to the `Auth::attempt` method when attempting to sign into an application. The method should then "query" the underlying persistent storage for the user matching those credentials. Typically, this method will run a query with a "where" condition on `$credentials['username']`. **This method should not attempt to do any password validation or authentication.** + +The `validateCredentials` method should compare the given `$user` with the `$credentials` to authenticate the user. For example, this method might compare the `$user->getAuthPassword()` string to a `Hash::make` of `$credentials['password']`. + +Now that we have explored each of the methods on the `UserProviderInterface`, let's take a look at the `UserInterface`. Remember, the provider should return implementations of this interface from the `retrieveById` and `retrieveByCredentials` methods: + + interface UserInterface { + + public function getAuthIdentifier(); + public function getAuthPassword(); + + } + +This interface is simple. The `getAuthIdentifier` method should return the "primary key" of the user. In a MySQL back-end, again, this would be the auto-incrementing primary key. The `getAuthPassword` should return the user's hashed password. This interface allows the authentication system to work with any User class, regardless of what ORM or storage abstraction layer you are using. By default, Laravel includes a `User` class in the `app/models` directory which implements this interface, so you may consult this class for an implementation example. + +Finally, once we have implemented the `UserProviderInterface`, we are ready to register our extension with the `Auth` facade: + + Auth::extend('riak', function($app) + { + return new RiakUserProvider($app['riak.connection']); + }); + +After you have registered the driver with the `extend` method, you switch to the new driver in your `app/config/auth.php` configuration file. + + +## IoC Based Extension + +Almost every service provider included with the Laravel framework binds objects into the IoC container. You can find a list of your application's service providers in the `app/config/app.php` configuration file. As you have time, you should skim through each of these provider's source code. By doing so, you will gain a much better understanding of what each provider adds to the framework, as well as what keys are used to bind various services into the IoC container. + +For example, the `HashServiceProvider` binds a `hash` key into the IoC container, which resolves into a `Illuminate\Hashing\BcryptHasher` instance. You can easily extend and override this class within your own application by overriding this IoC binding. For example: + + class SnappyHashProvider extends Illuminate\Hashing\HashServiceProvider { + + public function boot() + { + App::bindShared('hash', function() + { + return new Snappy\Hashing\ScryptHasher; + }); + + parent::boot(); + } + + } + +Note that this class extends the `HashServiceProvider`, not the default `ServiceProvider` base class. Once you have extended the service provider, swap out the `HashServiceProvider` in your `app/config/app.php` configuration file with the name of your extended provider. + +This is the general method of extending any core class that is bound in the container. Essentially every core class is bound in the container in this fashion, and can be overridden. Again, reading through the included framework service providers will familiarize you with where various classes are bound into the container, and what keys they are bound by. This is a great way to learn more about how Laravel is put together. + + +## Request Extension + +Because it is such a foundational piece of the framework and is instantiated very early in the request cycle, extending the `Request` class works a little differently than the previous examples. + +First, extend the class like normal: + + -## Introduction +## မိတ်ဆက် -Facades provide a "static" interface to classes that are available in the application's [service container](/docs/{{version}}/container). Laravel ships with many facades which provide access to almost all of Laravel's features. Laravel facades serve as "static proxies" to underlying classes in the service container, providing the benefit of a terse, expressive syntax while maintaining more testability and flexibility than traditional static methods. +Facades (ဖဆော့စ် ဟုအသံထွက်ပါ) က Application ရဲ့ [IoC container](ioc.md) ထဲမှာရှိတဲ့ Class တွေကို static ပုံစံမျိုးသုံးနိုင်အောင် လုပ်ပေးပါတယ်။ Laravel မှာလဲ Facades တွေအများကြီးပါဝင်ပြီးတော့ အဲဒီ Facade တွေကိုလည်း သုံးဖူးပါလိမ့်မယ်။ သင်သုံးဖူးပေမယ့်လည်း သုံးဖူးမှန်းမသိဖြစ်နေတက်ပါတယ်။ Laravel "facades" တွေက Static Proxy တွေအနေနဲ့ ကူညီပေးပါတယ်။ ၄င်းက သာမာန် Static method တွေမဟုတ်ဘဲ ၊ ဖတ်/မှတ်လို့ကောင်းပြီး ပိုပြီးတိုတောင်းတဲ့ Syntax ပုံစံတွေဖြစ်စေတဲ့အပြင် Test လုပ်လို့အဆင်ပြေပြီး ပြောင်းလွယ်ပြင်လွယ်ဖြစ်စေပါတယ်။ -All of Laravel's facades are defined in the `Illuminate\Support\Facades` namespace. So, we can easily access a facade like so: +အခါအားလျောက်စွာ သင့် Application နဲ့ Package တွေ အတွက် သင့်ကိုယ်ပိုင် Facades တွေတည်ဆောက်နိုင်ပါတယ်။ ဒါ့ကြောင့် ဒီ Class တွေရဲ့ အသုံးပြုပုံတွေ နဲ့ အယူအစတွေကို မွှေနှောက်ကြည့်ကြရအောင်။ - use Illuminate\Support\Facades\Cache; +> **မှတ်ချက်:** Facades ကိုမလေ့လာခင် ၊ Laravel ရဲ့ [IoC container](ioc.md) နဲ့သေချာရင်းနှီးနေဖို့ အကြံပြုချင်ပါတယ်။ - Route::get('/cache', function () { - return Cache::get('key'); - }); + +## ရှင်းလင်းချက် -Throughout the Laravel documentation, many of the examples will use facades to demonstrate various features of the framework. +Facade ဆိုတာ Class တစ်ခုဖြစ်ပြီး Container ထဲက Object ကို ခေါ်အသုံးပြုခွင့်ပေးပါတယ်။ ဒီလိုခေါ်သုံးနိုင်တာ `Facade` class ကြောင့်ဖြစ်ပါတယ်။ Laravel ရဲ့ Facade တွေ နဲ့ သင်ကိုယ်ပိုင်ဆောက်ထားတဲ့ Facade တွေအားလုံးဟာ `Facade` class ကို Extend ပြုလုပ်ရပါတယ်။ - -## When To Use Facades +သင့်ကိုယ်ပိုင် Facade class ဆောက်တော့မယ်ဆိုရင် `getFacadeAccessor` ဆိုတဲ့ method ကိုပဲ implement လုပ်ဖို့လိုပါမယ်။ `getFacadeAccessor` က Container ထဲကနေ ဘယ်ဟာကိုသုံးရမယ်လို့ ဆုံးဖြတ်ပေးပါတယ်။ သင့်ကိုယ်ပိုင် Facade ကနေ Resolved လုပ်ပြီးသား object ထဲကိုရွှေ့ပြောင်းဖို့အတွက် အခြေခံ `Facade` class မှာတော့ `__callStatic()` ဆိုတဲ့ magic-method ကိုသုံးထားပါတယ်။ -Facades have many benefits. They provide a terse, memorable syntax that allows you to use Laravel's features without remembering long class names that must be injected or configured manually. Furthermore, because of their unique usage of PHP's dynamic methods, they are easy to test. +ဒါ့ကြောင့် သင့်အနေနဲ့ `Cache::get` လိုမျိုး Facade တစ်ခုကို ခေါ်မယ်ဆိုရင် Laravel က Cache manager class ကို IoC container ထဲကနေဆွဲထုတ်ပြီး သူထဲက `get` method ကိုခေါ်ပေးပါတယ်။ နည်းပညာအခေါ်အဝေါ်အရဆိုရင်တော Laravel Facades တွေဆိုတာ Ioc container တွေကို service locator တစ်ခုအနေနဲ့အသုံးပြုနိုင်တဲ့ ရေး/ဖတ်/မှတ်ရလွယ်ကူသော syntax ဖြစ်ပါတယ်။ -However, some care must be taken when using facades. The primary danger of facades is class scope creep. Since facades are so easy to use and do not require injection, it can be easy to let your classes continue to grow and use many facades in a single class. Using dependency injection, this potential is mitigated by the visual feedback a large constructor gives you that your class is growing too large. So, when using facades, pay special attention to the size of your class so that it's scope of responsibility stays narrow. + +## လက်တွေ့အသုံးချခြင်း -> {tip} When building a third-party package that interacts with Laravel, it's better to inject [Laravel contracts](/docs/{{version}}/contracts) instead of using facades. Since packages are built outside of Laravel itself, you will not have access to Laravel's facade testing helpers. +အောက်ကအတိုင်းဆိုရင် ၊ Laravel cache system ကို ခေါ်တာပါ။ သာမာန်အပေါ်ယံအတိုင်း ကြည့်လိုက်မယ်ဆိုရင်တော့ `Cache` class ထဲက `get` ဆိုတဲ့ static method တစ်ခုကို ခေါ်လိုက်တယ်လို့ထင်ရပါတယ်။ - -### Facades Vs. Dependency Injection + $value = Cache::get('key'); -One of the primary benefits of dependency injection is the ability to swap implementations of the injected class. This is useful during testing since you can inject a mock or stub and assert that various methods were called on the stub. +ဒါပေမယ့် `Illuminate\Support\Facades\Cache` class ကိုကြည့်လိုက်မယ်ဆိုရင် `get` ဆိုတဲ့ static method လုံးဝမရှိပါဘူး -Typically, it would not be possible to mock or stub a truly static class method. However, since facades use dynamic methods to proxy method calls to objects resolved from the service container, we actually can test facades just as we would test an injected class instance. For example, given the following route: + class Cache extends Facade { - use Illuminate\Support\Facades\Cache; + /** + * Get the registered name of the component. + * + * @return string + */ + protected static function getFacadeAccessor() { return 'cache'; } - Route::get('/cache', function () { - return Cache::get('key'); - }); + } -We can write the following test to verify that the `Cache::get` method was called with the argument we expected: +Cache class က `Facade` class ကို extend လုပ်ထားပြီး `getFacadeAccessor()` ဆိုတာပဲရှိပါတယ်။ အဲဒီ Method ရဲ့တာဝန်က IoC နာမည်ကို return လုပ်ပေးယုံပါပဲ။ - use Illuminate\Support\Facades\Cache; +User က `Cache` facade ထဲက ဘယ် static method ကိုမဆို သုံးလိုက်မယ်ဆိုတာနဲ့ ၊ Laravel က IoC container ထဲကနေ `cache` ကိုခေါ်ပြီး ၊ ကိုယ်လိုချင်တဲ့ method (အခုအတိုင်းဆို `get`) ကို run ပေးပါတယ်။ - /** - * A basic functional test example. - * - * @return void - */ - public function testBasicExample() - { - Cache::shouldReceive('get') - ->with('key') - ->andReturn('value'); +ဒါ့ကြောင့် ၊ ကျွန်တော်တို့သုံးထားတဲ့ `Cache::get` ရဲ့ နောက်ကွယ်မှာက အောက်ကအတိုင်းရှိနေပါမယ်။ - $this->visit('/cache') - ->see('value'); - } + $value = $app->make('cache')->get('key'); - -### Facades Vs. Helper Functions + +## ကိုယ်ပိုင် Facades တည်ဆောက်ခြင်း -In addition to facades, Laravel includes a variety of "helper" functions which can perform common tasks like generating views, firing events, dispatching jobs, or sending HTTP responses. Many of these helper functions perform the same function as a corresponding facade. For example, this facade call and helper call are equivalent: +Creating a facade for your own application or package is simple. You only need 3 things: +ကိုယ့် application (ဒါမှမဟုတ်) package အတွက် ကိုယ်ပိုင် facade ဆောက်ရတာလွယ်ကူပါတယ်။ အဆင့် ၃ ဆင့်ပဲလိုပါတယ် : - return View::make('profile'); +- An IoC binding +- facade class တစ်ခု +- facade ကိုယ် ခေါ်မယ့် Alia သတ်မှတ်ပေးရန် - return view('profile'); +ဥပမာတစ်ခုလောက် ကြည့်ကြပါမယ်။ ကျွန်တော်တို့မှာ `PaymentGateway\Payment` ဆိုတဲ့ class တစ်ခုရှိမယ်ဆိုကြပါစို့ -There is absolutely no practical difference between facades and helper functions. When using helper functions, you may still test them exactly as you would the corresponding facade. For example, given the following route: + namespace PaymentGateway; - Route::get('/cache', function () { - return cache('key'); - }); + class Payment { -Under the hood, the `cache` helper is going to call the `get` method on the class underlying the `Cache` facade. So, even though we are using the helper function, we can write the following test to verify that the method was called with the argument we expected: + public function process() + { + // + } - use Illuminate\Support\Facades\Cache; + } - /** - * A basic functional test example. - * - * @return void - */ - public function testBasicExample() - { - Cache::shouldReceive('get') - ->with('key') - ->andReturn('value'); +ဒီ class က `app/models` directory ထဲမှာဖြစ်ဖြစ် (ဒါမှမဟုတ်) တစ်ခြား Composer က auto-load ပြုလုပ်နိုင်တဲ့ မည်သည့်နေရာတွင်မဆို တည်ရှိနိုင်ပါတယ်။ - $this->visit('/cache') - ->see('value'); - } +IoC container ထဲအဲဒီ class ကို ထည့်ပေးဖို့အတွက် bind လုပ်ဖို့လိုပါမယ်။ - -## How Facades Work + App::bind('payment', function() + { + return new \PaymentGateway\Payment; + }); -In a Laravel application, a facade is a class that provides access to an object from the container. The machinery that makes this work is in the `Facade` class. Laravel's facades, and any custom facades you create, will extend the base `Illuminate\Support\Facades\Facade` class. +ဒီ bind လုပ်ထားတာကို Register လုပ်ဖို့အတွက် အကောင်းဆုံးနည်းကတော့ `PaymentServiceProvider` ဆိုပြီး [service provider](ioc#service-providers.md) တစ်ခုဆောက်ပြီးတော့ အပေါ်က bind လုပ်ထားတာကို `register` ဆိုတဲ့ method ထဲ ထည့်ပေးလိုက်တာပါ။ အခုဆောက်ထားတဲ့ Service Provider ကို Laravel က load လုပ်ဖို့ဆိုရင်တော့ `app/config/app.php` ထဲမှာ သတ်မှတ်ပေးဖို့လိုပါမယ်။ -The `Facade` base class makes use of the `__callStatic()` magic-method to defer calls from your facade to an object resolved from the container. In the example below, a call is made to the Laravel cache system. By glancing at this code, one might assume that the static method `get` is being called on the `Cache` class: +Next, we can create our own facade class: +နောက်တစ်ဆင့်မှာတော့ ကိုယ်ပိုင် facade class ဆောက်နိုင်ပါပြီ - - $user]); - } - } +နောက်ဆုံးအနေနဲ့ ကျွန်တော်တို့ရဲ့ Facade ကို Alia (Shortcut) အနေနဲ့ခေါ်သုံးချင်တယ်ဆိုရင်တော့ `app/config/app.php` ထဲက `aliases` array ထဲမှာ သတ်မှတ်ပေးရပါမယ်။ အခုဆိုရင်တော့ `Payment` class ရဲ့ `process` method ကို အောက်ကအတိုင်း လွယ်လွယ်ကူကူပဲ ခေါ်နိုင်ပါပြီ- -Notice that near the top of the file we are "importing" the `Cache` facade. This facade serves as a proxy to accessing the underlying implementation of the `Illuminate\Contracts\Cache\Factory` interface. Any calls we make using the facade will be passed to the underlying instance of Laravel's cache service. + Payment::process(); -If we look at that `Illuminate\Support\Facades\Cache` class, you'll see that there is no static method `get`: +### Aliases တွေကို Auto-Load လုပ်တဲ့အခါ သတိထားစရာများ - class Cache extends Facade - { - /** - * Get the registered name of the component. - * - * @return string - */ - protected static function getFacadeAccessor() { return 'cache'; } - } +[PHP က type hint မသက်မှတ်ပေးထားတဲ့ class တွေကို autload လုပ်ပေးမှာမဟုတ်တဲ့အတွက်](https://bugs.php.net/bug.php?id=39003) `Aliases` array ထဲမှာ ရှိတဲ့ Class တွေကို တစ်ချို့သော instance တွေမှာ သုံးလို့မရပါဘူး။ `\ServiceWrapper\ApiTimeoutException` ကို `ApiTimeoutException` လို့ Alia လုပ်ထားလိုက်မယ်ဆိုရင် `\ServiceWrapper` namespace ရဲ့အပြင်ဖက်မှာ `catch(ApiTimeoutException $e)` လို့ခေါ်မယ်ဆိုရင် thrown လုပ်လိုက်ပေမယ့် ဘယ်တော့မှ catch လုပ်လို့မရပါဘူး။ ဒီလိုပြဿနာမျိုးကိုပဲ Model တွေမှာလဲ ကြုံတွေ့နိုင်ပါတယ်။ တစ်ခုတည်းသော ဖြေရှင်းနည်းကတော့ Alias တွေမသတ်မှတ်ဘဲ file ရဲ့အပေါ်ဆုံးမှာ `use` ဆိုပြီးသတ်မှတ်ပြီးသုံးတာပါပဲ။ -Instead, the `Cache` facade extends the base `Facade` class and defines the method `getFacadeAccessor()`. This method's job is to return the name of a service container binding. When a user references any static method on the `Cache` facade, Laravel resolves the `cache` binding from the [service container](/docs/{{version}}/container) and runs the requested method (in this case, `get`) against that object. + + +## Facades တွေကို Mock ပြုလုပ်ပေးခြင်း +Facade တွေ အဓိကရှိနေရခြင်းရဲ့အကြောင်းရင်းကတော့ Test လွယ်လွယ်ကူကူလုပ်နိုင်ဖို့ပဲဖြစ်ပါတယ်။ Mock လုပ်တဲ့အပိုင်းကိုတော့ [mocking facades](testing#mocking-facades.md) မှာ ပြည့်ပြည့်စုံစုံ ဖော်ပြပေးထားပါတယ်။ -## Facade Class Reference +## Facade Class ကိုကား -Below you will find every facade and its underlying class. This is a useful tool for quickly digging into the API documentation for a given facade root. The [service container binding](/docs/{{version}}/container) key is also included where applicable. +အောက်ကဇယားမှာတော့ ရှိသမျှ Facade တွေနဲ့ သူရဲ့နောက်ကွယ်က class တွေကို ဖော်ပြပေးထားပါတယ်။ API Documentation ထဲကို သက်ဆိုင်ရာ နေရာလိုက်လဲ ချိတ်ပေးထားပါတယ်။ [IoC binding](ioc.md) key ရှိတဲ့ Facade တွေကိုလဲ သူ့ key တွေရေးပေးထားပါတယ်။ -Facade | Class | Service Container Binding +Facade | Class | IoC Binding ------------- | ------------- | ------------- -App | [Illuminate\Foundation\Application](http://laravel.com/api/{{version}}/Illuminate/Foundation/Application.html) | `app` -Artisan | [Illuminate\Contracts\Console\Kernel](http://laravel.com/api/{{version}}/Illuminate/Contracts/Console/Kernel.html) | `artisan` -Auth | [Illuminate\Auth\AuthManager](http://laravel.com/api/{{version}}/Illuminate/Auth/AuthManager.html) | `auth` -Blade | [Illuminate\View\Compilers\BladeCompiler](http://laravel.com/api/{{version}}/Illuminate/View/Compilers/BladeCompiler.html) | `blade.compiler` -Bus | [Illuminate\Contracts\Bus\Dispatcher](http://laravel.com/api/{{version}}/Illuminate/Contracts/Bus/Dispatcher.html) | -Cache | [Illuminate\Cache\Repository](http://laravel.com/api/{{version}}/Illuminate/Cache/Repository.html) | `cache` -Config | [Illuminate\Config\Repository](http://laravel.com/api/{{version}}/Illuminate/Config/Repository.html) | `config` -Cookie | [Illuminate\Cookie\CookieJar](http://laravel.com/api/{{version}}/Illuminate/Cookie/CookieJar.html) | `cookie` -Crypt | [Illuminate\Encryption\Encrypter](http://laravel.com/api/{{version}}/Illuminate/Encryption/Encrypter.html) | `encrypter` -DB | [Illuminate\Database\DatabaseManager](http://laravel.com/api/{{version}}/Illuminate/Database/DatabaseManager.html) | `db` -DB (Instance) | [Illuminate\Database\Connection](http://laravel.com/api/{{version}}/Illuminate/Database/Connection.html) | -Event | [Illuminate\Events\Dispatcher](http://laravel.com/api/{{version}}/Illuminate/Events/Dispatcher.html) | `events` -File | [Illuminate\Filesystem\Filesystem](http://laravel.com/api/{{version}}/Illuminate/Filesystem/Filesystem.html) | `files` -Gate | [Illuminate\Contracts\Auth\Access\Gate](http://laravel.com/api/5.1/Illuminate/Contracts/Auth/Access/Gate.html) | -Hash | [Illuminate\Contracts\Hashing\Hasher](http://laravel.com/api/{{version}}/Illuminate/Contracts/Hashing/Hasher.html) | `hash` -Lang | [Illuminate\Translation\Translator](http://laravel.com/api/{{version}}/Illuminate/Translation/Translator.html) | `translator` -Log | [Illuminate\Log\Writer](http://laravel.com/api/{{version}}/Illuminate/Log/Writer.html) | `log` -Mail | [Illuminate\Mail\Mailer](http://laravel.com/api/{{version}}/Illuminate/Mail/Mailer.html) | `mailer` -Password | [Illuminate\Auth\Passwords\PasswordBroker](http://laravel.com/api/{{version}}/Illuminate/Auth/Passwords/PasswordBroker.html) | `auth.password` -Queue | [Illuminate\Queue\QueueManager](http://laravel.com/api/{{version}}/Illuminate/Queue/QueueManager.html) | `queue` -Queue (Instance) | [Illuminate\Contracts\Queue\Queue](http://laravel.com/api/{{version}}/Illuminate/Contracts/Queue/Queue.html) | `queue` -Queue (Base Class) | [Illuminate\Queue\Queue](http://laravel.com/api/{{version}}/Illuminate/Queue/Queue.html) | -Redirect | [Illuminate\Routing\Redirector](http://laravel.com/api/{{version}}/Illuminate/Routing/Redirector.html) | `redirect` -Redis | [Illuminate\Redis\Database](http://laravel.com/api/{{version}}/Illuminate/Redis/Database.html) | `redis` -Request | [Illuminate\Http\Request](http://laravel.com/api/{{version}}/Illuminate/Http/Request.html) | `request` -Response | [Illuminate\Contracts\Routing\ResponseFactory](http://laravel.com/api/{{version}}/Illuminate/Contracts/Routing/ResponseFactory.html) | -Route | [Illuminate\Routing\Router](http://laravel.com/api/{{version}}/Illuminate/Routing/Router.html) | `router` -Schema | [Illuminate\Database\Schema\Blueprint](http://laravel.com/api/{{version}}/Illuminate/Database/Schema/Blueprint.html) | -Session | [Illuminate\Session\SessionManager](http://laravel.com/api/{{version}}/Illuminate/Session/SessionManager.html) | `session` -Session (Instance) | [Illuminate\Session\Store](http://laravel.com/api/{{version}}/Illuminate/Session/Store.html) | -Storage | [Illuminate\Contracts\Filesystem\Factory](http://laravel.com/api/{{version}}/Illuminate/Contracts/Filesystem/Factory.html) | `filesystem` -URL | [Illuminate\Routing\UrlGenerator](http://laravel.com/api/{{version}}/Illuminate/Routing/UrlGenerator.html) | `url` -Validator | [Illuminate\Validation\Factory](http://laravel.com/api/{{version}}/Illuminate/Validation/Factory.html) | `validator` -Validator (Instance) | [Illuminate\Validation\Validator](http://laravel.com/api/{{version}}/Illuminate/Validation/Validator.html) | -View | [Illuminate\View\Factory](http://laravel.com/api/{{version}}/Illuminate/View/Factory.html) | `view` -View (Instance) | [Illuminate\View\View](http://laravel.com/api/{{version}}/Illuminate/View/View.html) | +App | [Illuminate\Foundation\Application](http://laravel.com/api/4.1/Illuminate/Foundation/Application.html) | `app` +Artisan | [Illuminate\Console\Application](http://laravel.com/api/4.1/Illuminate/Console/Application.html) | `artisan` +Auth | [Illuminate\Auth\AuthManager](http://laravel.com/api/4.1/Illuminate/Auth/AuthManager.html) | `auth` +Auth (Instance) | [Illuminate\Auth\Guard](http://laravel.com/api/4.1/Illuminate/Auth/Guard.html) | +Blade | [Illuminate\View\Compilers\BladeCompiler](http://laravel.com/api/4.1/Illuminate/View/Compilers/BladeCompiler.html) | `blade.compiler` +Cache | [Illuminate\Cache\Repository](http://laravel.com/api/4.1/Illuminate/Cache/Repository.html) | `cache` +Config | [Illuminate\Config\Repository](http://laravel.com/api/4.1/Illuminate/Config/Repository.html) | `config` +Cookie | [Illuminate\Cookie\CookieJar](http://laravel.com/api/4.1/Illuminate/Cookie/CookieJar.html) | `cookie` +Crypt | [Illuminate\Encryption\Encrypter](http://laravel.com/api/4.1/Illuminate/Encryption/Encrypter.html) | `encrypter` +DB | [Illuminate\Database\DatabaseManager](http://laravel.com/api/4.1/Illuminate/Database/DatabaseManager.html) | `db` +DB (Instance) | [Illuminate\Database\Connection](http://laravel.com/api/4.1/Illuminate/Database/Connection.html) | +Event | [Illuminate\Events\Dispatcher](http://laravel.com/api/4.1/Illuminate/Events/Dispatcher.html) | `events` +File | [Illuminate\Filesystem\Filesystem](http://laravel.com/api/4.1/Illuminate/Filesystem/Filesystem.html) | `files` +Form | [Illuminate\Html\FormBuilder](http://laravel.com/api/4.1/Illuminate/Html/FormBuilder.html) | `form` +Hash | [Illuminate\Hashing\HasherInterface](http://laravel.com/api/4.1/Illuminate/Hashing/HasherInterface.html) | `hash` +HTML | [Illuminate\Html\HtmlBuilder](http://laravel.com/api/4.1/Illuminate/Html/HtmlBuilder.html) | `html` +Input | [Illuminate\Http\Request](http://laravel.com/api/4.1/Illuminate/Http/Request.html) | `request` +Lang | [Illuminate\Translation\Translator](http://laravel.com/api/4.1/Illuminate/Translation/Translator.html) | `translator` +Log | [Illuminate\Log\Writer](http://laravel.com/api/4.1/Illuminate/Log/Writer.html) | `log` +Mail | [Illuminate\Mail\Mailer](http://laravel.com/api/4.1/Illuminate/Mail/Mailer.html) | `mailer` +Paginator | [Illuminate\Pagination\Factory](http://laravel.com/api/4.1/Illuminate/Pagination/Factory.html) | `paginator` +Paginator (Instance) | [Illuminate\Pagination\Paginator](http://laravel.com/api/4.1/Illuminate/Pagination/Paginator.html) | +Password | [Illuminate\Auth\Reminders\PasswordBroker](http://laravel.com/api/4.1/Illuminate/Auth/Reminders/PasswordBroker.html) | `auth.reminder` +Queue | [Illuminate\Queue\QueueManager](http://laravel.com/api/4.1/Illuminate/Queue/QueueManager.html) | `queue` +Queue (Instance) | [Illuminate\Queue\QueueInterface](http://laravel.com/api/4.1/Illuminate/Queue/QueueInterface.html) | +Queue (Base Class) | [Illuminate\Queue\Queue](http://laravel.com/api/4.1/Illuminate/Queue/Queue.html) | +Redirect | [Illuminate\Routing\Redirector](http://laravel.com/api/4.1/Illuminate/Routing/Redirector.html) | `redirect` +Redis | [Illuminate\Redis\Database](http://laravel.com/api/4.1/Illuminate/Redis/Database.html) | `redis` +Request | [Illuminate\Http\Request](http://laravel.com/api/4.1/Illuminate/Http/Request.html) | `request` +Response | [Illuminate\Support\Facades\Response](http://laravel.com/api/4.1/Illuminate/Support/Facades/Response.html) | +Route | [Illuminate\Routing\Router](http://laravel.com/api/4.1/Illuminate/Routing/Router.html) | `router` +Schema | [Illuminate\Database\Schema\Blueprint](http://laravel.com/api/4.1/Illuminate/Database/Schema/Blueprint.html) | +Session | [Illuminate\Session\SessionManager](http://laravel.com/api/4.1/Illuminate/Session/SessionManager.html) | `session` +Session (Instance) | [Illuminate\Session\Store](http://laravel.com/api/4.1/Illuminate/Session/Store.html) | +SSH | [Illuminate\Remote\RemoteManager](http://laravel.com/api/4.1/Illuminate/Remote/RemoteManager.html) | `remote` +SSH (Instance) | [Illuminate\Remote\Connection](http://laravel.com/api/4.1/Illuminate/Remote/Connection.html) | +URL | [Illuminate\Routing\UrlGenerator](http://laravel.com/api/4.1/Illuminate/Routing/UrlGenerator.html) | `url` +Validator | [Illuminate\Validation\Factory](http://laravel.com/api/4.1/Illuminate/Validation/Factory.html) | `validator` +Validator (Instance) | [Illuminate\Validation\Validator](http://laravel.com/api/4.1/Illuminate/Validation/Validator.html) +View | [Illuminate\View\Factory](http://laravel.com/api/4.1/Illuminate/View/Factory.html) | `view` +View (Instance) | [Illuminate\View\View](http://laravel.com/api/4.1/Illuminate/View/View.html) | \ No newline at end of file diff --git a/filesystem.md b/filesystem.md deleted file mode 100644 index 5d5a2f8..0000000 --- a/filesystem.md +++ /dev/null @@ -1,326 +0,0 @@ -# Filesystem / Cloud Storage - -- [Introduction](#introduction) -- [Configuration](#configuration) - - [The Public Disk](#the-public-disk) - - [The Local Driver](#the-local-driver) - - [Other Driver Prerequisites](#other-driver-prerequisites) -- [Obtaining Disk Instances](#obtaining-disk-instances) -- [Retrieving Files](#retrieving-files) - - [File URLs](#file-urls) - - [File Metadata](#file-metadata) -- [Storing Files](#storing-files) - - [File Uploads](#file-uploads) - - [File Visibility](#file-visibility) -- [Deleting Files](#deleting-files) -- [Directories](#directories) -- [Custom Filesystems](#custom-filesystems) - - -## Introduction - -Laravel provides a powerful filesystem abstraction thanks to the wonderful [Flysystem](https://github.com/thephpleague/flysystem) PHP package by Frank de Jonge. The Laravel Flysystem integration provides simple to use drivers for working with local filesystems, Amazon S3, and Rackspace Cloud Storage. Even better, it's amazingly simple to switch between these storage options as the API remains the same for each system. - - -## Configuration - -The filesystem configuration file is located at `config/filesystems.php`. Within this file you may configure all of your "disks". Each disk represents a particular storage driver and storage location. Example configurations for each supported driver are included in the configuration file. So, simply modify the configuration to reflect your storage preferences and credentials. - -Of course, you may configure as many disks as you like, and may even have multiple disks that use the same driver. - - -### The Public Disk - -The `public` disk is intended for files that are going to be publicly accessible. By default, the `public` disk uses the `local` driver and stores these files in `storage/app/public`. To make them accessible from the web, you should create a symbolic link from `public/storage` to `storage/app/public`. This convention will keep your publicly accessible files in one directory that can be easily shared across deployments when using zero down-time deployment systems like [Envoyer](https://envoyer.io). - -To create the symbolic link, you may use the `storage:link` Artisan command: - - php artisan storage:link - -Of course, once a file has been stored and the symbolic link has been created, you can create a URL to the files using the `asset` helper: - - echo asset('storage/file.txt'); - - -### The Local Driver - -When using the `local` driver, all file operations are relative to the `root` directory defined in your configuration file. By default, this value is set to the `storage/app` directory. Therefore, the following method would store a file in `storage/app/file.txt`: - - Storage::disk('local')->put('file.txt', 'Contents'); - - -### Other Driver Prerequisites - -#### Composer Packages - -Before using the S3 or Rackspace drivers, you will need to install the appropriate package via Composer: - -- Amazon S3: `league/flysystem-aws-s3-v3 ~1.0` -- Rackspace: `league/flysystem-rackspace ~1.0` - -#### FTP Driver Configuration - -Laravel's Flysystem integrations works great with FTP; however, a sample configuration is not included with the framework's default `filesystems.php` configuration file. If you need to configure a FTP filesystem, you may use the example configuration below: - - 'ftp' => [ - 'driver' => 'ftp', - 'host' => 'ftp.example.com', - 'username' => 'your-username', - 'password' => 'your-password', - - // Optional FTP Settings... - // 'port' => 21, - // 'root' => '', - // 'passive' => true, - // 'ssl' => true, - // 'timeout' => 30, - ], - -#### Rackspace Driver Configuration - -Laravel's Flysystem integrations works great with Rackspace; however, a sample configuration is not included with the framework's default `filesystems.php` configuration file. If you need to configure a Rackspace filesystem, you may use the example configuration below: - - 'rackspace' => [ - 'driver' => 'rackspace', - 'username' => 'your-username', - 'key' => 'your-key', - 'container' => 'your-container', - 'endpoint' => 'https://identity.api.rackspacecloud.com/v2.0/', - 'region' => 'IAD', - 'url_type' => 'publicURL', - ], - - -## Obtaining Disk Instances - -The `Storage` facade may be used to interact with any of your configured disks. For example, you may use the `put` method on the facade to store an avatar on the default disk. If you call methods on the `Storage` facade without first calling the `disk` method, the method call will automatically be passed to the default disk: - - use Illuminate\Support\Facades\Storage; - - Storage::put('avatars/1', $fileContents); - -If your applications interacts with multiple disks, you may use the `disk` method on the `Storage` facade to work with files on a particular disk: - - Storage::disk('s3')->put('avatars/1', $fileContents); - - -## Retrieving Files - -The `get` method may be used to retrieve the contents of a file. The raw string contents of the file will be returned by the method. Remember, all file paths should be specified relative to the "root" location configured for the disk: - - $contents = Storage::get('file.jpg'); - -The `exists` method may be used to determine if a file exists on the disk: - - $exists = Storage::disk('s3')->exists('file.jpg'); - - -### File URLs - -When using the `local` or `s3` drivers, you may use the `url` method to get the URL for the given file. If you are using the `local` driver, this will typically just prepend `/storage` to the given path and return a relative URL to the file. If you are using the `s3` driver, the fully qualified remote URL will be returned: - - use Illuminate\Support\Facades\Storage; - - $url = Storage::url('file1.jpg'); - -> {note} Remember, if you are using the `local` driver, all files that should be publicly accessible should be placed in the `storage/public` directory. Furthermore, you should [create a symbolic link](#the-public-disk) to the `storage/public` directory. - - -### File Metadata - -In addition to reading and writing files, Laravel can also provide information about the files themselves. For example, the `size` method may be used to get the size of the file in bytes: - - use Illuminate\Support\Facades\Storage; - - $size = Storage::size('file1.jpg'); - -The `lastModified` method returns the UNIX timestamp of the last time the file was modified: - - $time = Storage::lastModified('file1.jpg'); - - -## Storing Files - -The `put` method may be used to store a file on disk. You may also pass a PHP `resource` to the `put` method, which will use Flysystem's underlying stream support. Using streams is greatly recommended when dealing with large files: - - use Illuminate\Support\Facades\Storage; - - Storage::put('file.jpg', $contents); - - Storage::put('file.jpg', $resource); - -#### Prepending & Appending To Files - -The `prepend` and `append` methods allow you to write to the beginning or end of a file: - - Storage::prepend('file.log', 'Prepended Text'); - - Storage::append('file.log', 'Appended Text'); - -#### Copying & Moving Files - -The `copy` method may be used to copy an existing file to a new location on the disk, while the `move` method may be used to rename or move an existing file to a new location: - - Storage::copy('old/file1.jpg', 'new/file1.jpg'); - - Storage::move('old/file1.jpg', 'new/file1.jpg'); - - -### File Uploads - -In web applications, one of the most common use-cases for storing files is storing user uploaded files such as profile pictures, photos, and documents. Laravel makes it very easy to store uploaded files using the `store` method on an uploaded file instance. Simply call the `store` method with the path at which you wish to store the uploaded file: - - file('avatar')->store('avatars'); - - return $path; - } - } - -There are a few important things to note about this example. Note that we only specified a directory name, not a file name. By default, the `store` method will automatically generate a filename based on the contents of the file. This is accomplished by taking a MD5 hash of the file's contents. The path to the file will be returned by the `store` method so you can store the path, including the generated file name, in your database. - -> {note} If you are receiving very large file uploads, you may wish to manually specify the file name as shown below. Calculating an MD5 hash for extremely large files can be memory intensive. - -#### Specifying A File Name - -If you would not like a file name to be automatically assigned to your stored file, you may use the `storeAs` method, which receives the path, the file name, and the (optional) disk as its arguments: - - $path = $request->file('avatar')->storeAs( - 'avatars', $request->user()->id - ); - -#### Specifying A Disk - -By default, this method will use your default disk. If you would like to specify another disk, pass the disk name as the second argument to the `store` method: - - $path = $request->file('avatar')->store( - 'avatars/'.$request->user()->id, 's3' - ); - - -### File Visibility - -In Laravel's Flysystem integration, "visibility" is an abstraction of file permissions across multiple platforms. Files may either be declared `public` or `private`. When a file is declared `public`, you are indicating that the file should generally be accessile to others. For example, when using the S3 driver, you may retrieve URLs for `public` files. - -You can set the visibility when setting the file via the `put` method: - - use Illuminate\Support\Facades\Storage; - - Storage::put('file.jpg', $contents, 'public'); - -If the file has already been stored, its visibility can be retrieved and set via the `getVisibility` and `setVisibility` methods: - - $visibility = Storage::getVisibility('file.jpg'); - - Storage::setVisibility('file.jpg', 'public') - - -## Deleting Files - -The `delete` method accepts a single filename or an array of files to remove from the disk: - - use Illuminate\Support\Facades\Storage; - - Storage::delete('file.jpg'); - - Storage::delete(['file1.jpg', 'file2.jpg']); - - -## Directories - -#### Get All Files Within A Directory - -The `files` method returns an array of all of the files in a given directory. If you would like to retrieve a list of all files within a given directory including all sub-directories, you may use the `allFiles` method: - - use Illuminate\Support\Facades\Storage; - - $files = Storage::files($directory); - - $files = Storage::allFiles($directory); - -#### Get All Directories Within A Directory - -The `directories` method returns an array of all the directories within a given directory. Additionally, you may use the `allDirectories` method to get a list of all directories within a given directory and all of its sub-directories: - - $directories = Storage::directories($directory); - - // Recursive... - $directories = Storage::allDirectories($directory); - -#### Create A Directory - -The `makeDirectory` method will create the given directory, including any needed sub-directories: - - Storage::makeDirectory($directory); - -#### Delete A Directory - -Finally, the `deleteDirectory` may be used to remove a directory and all of its files: - - Storage::deleteDirectory($directory); - - -## Custom Filesystems - -Laravel's Flysystem integration provides drivers for several "drivers" out of the box; however, Flysystem is not limited to these and has adapters for many other storage systems. You can create a custom driver if you want to use one of these additional adapters in your Laravel application. - -In order to set up the custom filesystem you will need to create a [service provider](/docs/{{version}}/providers) such as `DropboxServiceProvider`. In the provider's `boot` method, you may use the `Storage` facade's `extend` method to define the custom driver: - - -## Introduction - -The Laravel `Hash` [facade](/docs/{{version}}/facades) provides secure Bcrypt hashing for storing user passwords. If you are using the built-in `LoginController` and `RegisterController` classes that are included with your Laravel application, they will automatically use Bcrypt for registration and authentication. - -> {tip} Bcrypt is a great choice for hashing passwords because its "work factor" is adjustable, which means that the time it takes to generate a hash can be increased as hardware power increases. - - -## Basic Usage - -You may hash a password by calling the `make` method on the `Hash` facade: - - user()->fill([ - 'password' => Hash::make($request->newPassword) - ])->save(); - } - } - -#### Verifying A Password Against A Hash - -The `check` method allows you to verify that a given plain-text string corresponds to a given hash. However, if you are using the `LoginController` [included with Laravel](/docs/{{version}}/authentication), you will probably not need to use this directly, as this controller automatically calls this method: - - if (Hash::check('plain-text', $hashedPassword)) { - // The passwords match... - } - -#### Checking If A Password Needs To Be Rehashed - -The `needsRehash` function allows you to determine if the work factor used by the hasher has changed since the password was hashed: - - if (Hash::needsRehash($hashed)) { - $hashed = Hash::make('plain-text'); - } diff --git a/helpers.md b/helpers.md index 44e73e5..c78ebfd 100644 --- a/helpers.md +++ b/helpers.md @@ -1,930 +1,414 @@ -# Helper Functions - -- [Introduction](#introduction) -- [Available Methods](#available-methods) - - -## Introduction - -Laravel includes a variety of global "helper" PHP functions. Many of these functions are used by the framework itself; however, you are free to use them in your own applications if you find them convenient. - - -## Available Methods - - - -### Arrays - -
    - -[array_add](#method-array-add) -[array_collapse](#method-array-collapse) -[array_divide](#method-array-divide) -[array_dot](#method-array-dot) -[array_except](#method-array-except) -[array_first](#method-array-first) -[array_flatten](#method-array-flatten) -[array_forget](#method-array-forget) -[array_get](#method-array-get) -[array_has](#method-array-has) -[array_last](#method-array-last) -[array_only](#method-array-only) -[array_pluck](#method-array-pluck) -[array_pull](#method-array-pull) -[array_set](#method-array-set) -[array_sort](#method-array-sort) -[array_sort_recursive](#method-array-sort-recursive) -[array_where](#method-array-where) -[head](#method-head) -[last](#method-last) -
    - -### Paths - -
    - -[app_path](#method-app-path) -[base_path](#method-base-path) -[config_path](#method-config-path) -[database_path](#method-database-path) -[elixir](#method-elixir) -[public_path](#method-public-path) -[resource_path](#method-resource-path) -[storage_path](#method-storage-path) - -
    - -### Strings - -
    - -[camel_case](#method-camel-case) -[class_basename](#method-class-basename) -[e](#method-e) -[ends_with](#method-ends-with) -[snake_case](#method-snake-case) -[str_limit](#method-str-limit) -[starts_with](#method-starts-with) -[str_contains](#method-str-contains) -[str_finish](#method-str-finish) -[str_is](#method-str-is) -[str_plural](#method-str-plural) -[str_random](#method-str-random) -[str_singular](#method-str-singular) -[str_slug](#method-str-slug) -[studly_case](#method-studly-case) -[title_case](#method-title-case) -[trans](#method-trans) -[trans_choice](#method-trans-choice) - -
    - -### URLs - -
    - -[action](#method-action) -[asset](#method-asset) -[secure_asset](#method-secure-asset) -[route](#method-route) -[url](#method-url) - -
    - -### Miscellaneous - -
    - -[abort](#method-abort) -[abort_if](#method-abort-if) -[abort_unless](#method-abort-unless) -[auth](#method-auth) -[back](#method-back) -[bcrypt](#method-bcrypt) -[collect](#method-collect) -[config](#method-config) -[csrf_field](#method-csrf-field) -[csrf_token](#method-csrf-token) -[dd](#method-dd) -[dispatch](#method-dispatch) -[env](#method-env) -[event](#method-event) -[factory](#method-factory) -[method_field](#method-method-field) -[old](#method-old) -[redirect](#method-redirect) -[request](#method-request) -[response](#method-response) -[session](#method-session) -[value](#method-value) -[view](#method-view) - -
    - - -## Method Listing - - +# အကူ Function မ်ား + +- [Arrays](#arrays) +- [Paths](#paths) +- [Strings](#strings) +- [URLs](#urls) +- [Miscellaneous](#miscellaneous) ## Arrays - -#### `array_add()` {#collection-method .first-collection-method} - -The `array_add` function adds a given key / value pair to the array if the given key doesn't already exist in the array: - - $array = array_add(['name' => 'Desk'], 'price', 100); - - // ['name' => 'Desk', 'price' => 100] - - -#### `array_collapse()` {#collection-method} - -The `array_collapse` function collapses an array of arrays into a single array: - - $array = array_collapse([[1, 2, 3], [4, 5, 6], [7, 8, 9]]); - - // [1, 2, 3, 4, 5, 6, 7, 8, 9] - - -#### `array_divide()` {#collection-method} - -The `array_divide` function returns two arrays, one containing the keys, and the other containing the values of the original array: - - list($keys, $values) = array_divide(['name' => 'Desk']); - - // $keys: ['name'] - - // $values: ['Desk'] - - -#### `array_dot()` {#collection-method} - -The `array_dot` function flattens a multi-dimensional array into a single level array that uses "dot" notation to indicate depth: - - $array = array_dot(['foo' => ['bar' => 'baz']]); - - // ['foo.bar' => 'baz']; - - -#### `array_except()` {#collection-method} - -The `array_except` function removes the given key / value pairs from the array: +### array_add - $array = ['name' => 'Desk', 'price' => 100]; +`array_add` function သည္ အကယ္၍ ပထမ argument array တြင္ထပ္မံေပး လုိက္ေသာ key နွင့္ တန္ဖုိး အတြဲ ရွိျပီးသား မဟုတ္ခဲ့ပါက ထုိ key နွင့္ တန္ဖုိးအတြဲအား ထပ္မံေပါင္းထည့္ေပးပါသည္။ - $array = array_except($array, ['price']); + $array = array('foo' => 'bar'); - // ['name' => 'Desk'] + $array = array_add($array, 'key', 'value'); - -#### `array_first()` {#collection-method} +### array_divide -The `array_first` function returns the first element of an array passing a given truth test: +`array_divide` function သည္ မူလ array အား key မ်ားပါ၀င္ေသာ array နွင့္ တန္ဖုိးမ်ား ပါ ၀င္ေသာ array နွစ္ခု ပါ၀င္ေသာ array အျဖစ္ return ျပန္ေပးပါသည္။ - $array = [100, 200, 300]; + $array = array('foo' => 'bar'); - $value = array_first($array, function ($value, $key) { - return $value >= 150; - }); + list($keys, $values) = array_divide($array); - // 200 +### array_dot -A default value may also be passed as the third parameter to the method. This value will be returned if no value passes the truth test: +`array_dot` function သည္ dimension တစ္ခုထက္ပုိ၍ ပါ၀င္ေသာ array တစ္ခုကုိ "." သေကၤတသုံးေရးနည္းျဖင့္ အဆင့္ဆင့္ေခါ္ယူနုိင္ေသာ dimension တစ္ခုတည္း ရွိ array တစ္ခု အျဖစ္ေျပာင္းလဲေပးပါသည္။ - $value = array_first($array, $callback, $default); + $array = array('foo' => array('bar' => 'baz')); +ၡ + $array = array_dot($array); - -#### `array_flatten()` {#collection-method} + // array('foo.bar' => 'baz'); -The `array_flatten` function will flatten a multi-dimensional array into a single level. +### array_except - $array = ['name' => 'Joe', 'languages' => ['PHP', 'Ruby']]; +`array_except` method သည္ ေပးလုိက္ေသာ key နွင့္ တန္ဖုိး အတြဲကုိ ပထမ argument array ထံမွ ဖယ္ရွားေပးပါသည္။ - $array = array_flatten($array); + $array = array_except($array, array('keys', 'to', 'remove')); - // ['Joe', 'PHP', 'Ruby']; +### array_fetch - -#### `array_forget()` {#collection-method} +`array_fetch` method သည္ ပထမ argument array အတြင္းတြင္ အဆင့္ဆင့္ ညွပ္သုံးထားေသာ ေပးထားသည့္ ဒုတိယ argument နွင့္ ကုိက္ညီသည့္ nested array element မ်ားအား တစ္ဆင့္တည္း flattened လုပ္ထားေသာ array အျဖစ္ျဖင့္ return ျပန္ေပးပါသည္။ -The `array_forget` function removes a given key / value pair from a deeply nested array using "dot" notation: + $array = array( + array('developer' => array('name' => 'Taylor')), + array('developer' => array('name' => 'Dayle')), + ); - $array = ['products' => ['desk' => ['price' => 100]]]; + $array = array_fetch($array, 'developer.name'); - array_forget($array, 'products.desk'); + // array('Taylor', 'Dayle'); - // ['products' => []] +### array_first - -#### `array_get()` {#collection-method} +`array_first` method သည္ ေပးထားေသာ array အတြင္း မွ ေပးထားေသာ truth test ကုိ ေျပလည္ ေစ မည့္ ပထမဆုံး element အား return ျပန္ေပးပါသည္။ -The `array_get` function retrieves a value from a deeply nested array using "dot" notation: + $array = array(100, 200, 300); - $array = ['products' => ['desk' => ['price' => 100]]]; + $value = array_first($array, function($key, $value) + { + return $value >= 150; + }); - $value = array_get($array, 'products.desk'); +default တန္ဖုိးတစ္ခုကုိ လည္း တတိယ parameter အျဖစ္ ထည့္သြင္းေပးနုိင္ပါသည္။ - // ['price' => 100] + $value = array_first($array, $callback, $default); -The `array_get` function also accepts a default value, which will be returned if the specific key is not found: +### array_last - $value = array_get($array, 'names.john', 'default'); +`array_last` method သည္ ေပးထားေသာ array အတြင္းမွ ေပးထားေသာ truth test ကုိ ေျပလည္ေစမည့္ ေနာက္ဆုံး element အား return ျပန္ေပးပါသည္။ - -#### `array_has()` {#collection-method} + $array = array(350, 400, 500, 300, 200, 100); -The `array_has` function checks that a given item exists in an array using "dot" notation: + $value = array_last($array, function($key, $value) + { + return $value > 350; + }); - $array = ['products' => ['desk' => ['price' => 100]]]; + // 500 - $hasDesk = array_has($array, 'products.desk'); +default တန္ဖုိးတစ္ခုကုိ လည္း တတိယ parameter အျဖစ္ ထည့္သြင္းေပးနုိင္ပါသည္။ - // true + $value = array_last($array, $callback, $default); - -#### `array_last()` {#collection-method} +### array_flatten -The `array_last` function returns the last element of an array passing a given truth test: +`array_flatten` method သည္ ေပးထားေသာ dimension တစ္ခုထက္ပုိသည့္ array တစ္ခုကို တစ္ဆင့္တည္း ရွိေသာ array တစ္ခု အျဖစ္ return ျပန္ေပးပါသည္။ - $array = [100, 200, 300, 110]; + $array = array('name' => 'Joe', 'languages' => array('PHP', 'Ruby')); - $value = array_last($array, function ($value, $key) { - return $value >= 150; - }); + $array = array_flatten($array); - // 300 + // array('Joe', 'PHP', 'Ruby'); - -#### `array_only()` {#collection-method} +### array_forget -The `array_only` function will return only the specified key / value pairs from the given array: +`array_forget` method သည္ အဆင့္ဆင့္နက္နဲစြာ ညွပ္ထားေသာ deeply nested array တစ္ခုမွ "." သေကၤတသုံးေရးနည္းကုိ အသုံးျပု၍ ေရးထားေသာ ေပးရင္း key နွင့္ တန္ဖုိး အတြဲကုိ ဖယ္ရွားေပးပါသည္။ - $array = ['name' => 'Desk', 'price' => 100, 'orders' => 10]; + $array = array('names' => array('joe' => array('programmer'))); - $array = array_only($array, ['name', 'price']); + array_forget($array, 'names.joe'); - // ['name' => 'Desk', 'price' => 100] +### array_get - -#### `array_pluck()` {#collection-method} +`array_get` method သည္ အဆင့္ဆင့္နက္နဲစြာ ညွပ္ထားေသာ deeply nested array တစ္ခုမွ "." သေကၤတသုံးေရးနည္းကုိ အသုံးျပု၍ ေရးထားေသာ ေပးရင္း key နွင့္ တန္ဖုိး အတြဲကုိ ထုတ္ယူေပးပါသည္။ -The `array_pluck` function will pluck a list of the given key / value pairs from the array: + $array = array('names' => array('joe' => array('programmer'))); - $array = [ - ['developer' => ['id' => 1, 'name' => 'Taylor']], - ['developer' => ['id' => 2, 'name' => 'Abigail']], - ]; + $value = array_get($array, 'names.joe'); - $array = array_pluck($array, 'developer.name'); +>**မွတ္ခ်က္** အကယ္၍ `array_get` ၏ အလုပ္လုပ္ပုံမ် ိုး ကုိ object မ်ားတြင္ သုံးလုိပါက `object_get` အားသုံးနုိင္ပါသည္။ - // ['Taylor', 'Abigail']; +### array_only -You may also specify how you wish the resulting list to be keyed: +`array_only` method သည္ ပထမ argument array အတြင္းမွ ေပးထားေသာ key သုိ့မဟုတ္ တန္ဖုိးမ်ား ပါ၀င္သည့္ အတြဲမ်ားကုိသာ return ျပန္ေပးပါသည္။ - $array = array_pluck($array, 'developer.name', 'developer.id'); + $array = array('name' => 'Joe', 'age' => 27, 'votes' => 1); - // [1 => 'Taylor', 2 => 'Abigail']; + $array = array_only($array, array('name', 'votes')); - -#### `array_prepend()` {#collection-method} +### array_pluck -The `array_prepend` function will push an item onto the beginning of an array: +`array_pluck` method သည္ ပထမ argument array ထံမွ ေပးထားေသာ key သို့ မဟုတ္ တန္ဖုိး ပါ၀င္သည့္ အတြဲကုိသာ return ျပန္ေပးပါသည္။ - $array = ['one', 'two', 'three', 'four']; + $array = array(array('name' => 'Taylor'), array('name' => 'Dayle')); - $array = array_prepend($array, 'zero'); + $array = array_pluck($array, 'name'); - // $array: ['zero', 'one', 'two', 'three', 'four'] + // array('Taylor', 'Dayle'); - -#### `array_pull()` {#collection-method} +### array_pull -The `array_pull` function returns and removes a key / value pair from the array: +`array_pull` method သည္ ပထမ argument array ထံမွ ေပးထားေသာ key သုိ့ မဟုတ္ တန္ဖုိးပါ၀င္သည့္ အတြဲ ကုိ return ျပန္ျပီး ထုိ အတြဲအား မူလ array ထံမွလည္း ဖယ္ရွားေပးပါသည္။ - $array = ['name' => 'Desk', 'price' => 100]; + $array = array('name' => 'Taylor', 'age' => 27); - $name = array_pull($array, 'name'); + $name = array_pull($array, 'name'); - // $name: Desk +### array_set - // $array: ['price' => 100] +`array_set` method သည္ အဆင့္ဆင့္နက္နဲစြာ ညွပ္ထားေသာ array တစ္ခုအတြင္းမွ "." သေကၤတသုံးေရးနည္းကုိ အသုံးျပု၍ ေရးထားေသာ ဒုတိယ argument နွင့္ကုိက္ညီသည့္ တန္ဖုိးအား ျပု ျပင္ထည့္သြင္းေပးပါသည္။ - -#### `array_set()` {#collection-method} + $array = array('names' => array('programmer' => 'Joe')); -The `array_set` function sets a value within a deeply nested array using "dot" notation: + array_set($array, 'names.editor', 'Taylor'); - $array = ['products' => ['desk' => ['price' => 100]]]; +### array_sort - array_set($array, 'products.desk.price', 200); +`array_sort` method သည္ ေပးထားေသာ array အား ေပးထားေသာ Closure function ၏ ရလဒ္ကုိ အသုံးျပု ၍ စီေပးပါသည္။ - // ['products' => ['desk' => ['price' => 200]]] + $array = array( + array('name' => 'Jill'), + array('name' => 'Barry'), + ); - -#### `array_sort()` {#collection-method} + $array = array_values(array_sort($array, function($value) + { + return $value['name']; + })); -The `array_sort` function sorts the array by the results of the given Closure: +### array_where - $array = [ - ['name' => 'Desk'], - ['name' => 'Chair'], - ]; +`array_where` သည္ ေပးထားေသာ array အား ေပးထားေသာ Closure function တစ္ခုျဖင့္ filter လုပ္ေပးပါသည္။ - $array = array_values(array_sort($array, function ($value) { - return $value['name']; - })); + $array = array(100, '200', 300, '400', 500); - /* - [ - ['name' => 'Chair'], - ['name' => 'Desk'], - ] - */ + $array = array_where($array, function($key, $value) + { + return is_string($value); + }); - -#### `array_sort_recursive()` {#collection-method} + // Array ( [1] => 200 [3] => 400 ) -The `array_sort_recursive` function recursively sorts the array using the `sort` function: +### head - $array = [ - [ - 'Roman', - 'Taylor', - 'Li', - ], - [ - 'PHP', - 'Ruby', - 'JavaScript', - ], - ]; +array တစ္ခု၏ ပထမဆုံး element ကုိ return ျပန္ေပးပါသည္။ PHP 5.3.x တြင္ အသုံးျပုနုိင္ေသာ method chaining အတြက္ အသုံး၀င္ပါသည္။ - $array = array_sort_recursive($array); + $first = head($this->returnsArray('foo')); - /* - [ - [ - 'Li', - 'Roman', - 'Taylor', - ], - [ - 'JavaScript', - 'PHP', - 'Ruby', - ] - ]; - */ +### last - -#### `array_where()` {#collection-method} +array တစ္ခု၏ ေနာက္ဆုံး element ကို return ျပန္ေပးပါသည္။ method chaining အတြက္ အသုံး၀င္ပါသည္။ -The `array_where` function filters the array using the given Closure: - - $array = [100, '200', 300, '400', 500]; - - $array = array_where($array, function ($value, $key) { - return is_string($value); - }); - - // [1 => 200, 3 => 400] - - -#### `head()` {#collection-method} - -The `head` function simply returns the first element in the given array: - - $array = [100, 200, 300]; - - $first = head($array); - - // 100 - - -#### `last()` {#collection-method} - -The `last` function returns the last element in the given array: - - $array = [100, 200, 300]; - - $last = last($array); - - // 300 + $last = last($this->returnsArray('foo')); ## Paths - -#### `app_path()` {#collection-method} - -The `app_path` function returns the fully qualified path to the `app` directory. You may also use the `app_path` function to generate a fully qualified path to a file relative to the application directory: - - $path = app_path(); - - $path = app_path('Http/Controllers/Controller.php'); - - -#### `base_path()` {#collection-method} - -The `base_path` function returns the fully qualified path to the project root. You may also use the `base_path` function to generate a fully qualified path to a given file relative to the application directory: +### app_path - $path = base_path(); +`app` directory၏ path အျပည့္အစုံကုိ ေပးပါသည္။ - $path = base_path('vendor/bin'); + $path = app_path(); - -#### `config_path()` {#collection-method} +### base_path -The `config_path` function returns the fully qualified path to the application configuration directory: +application ကုိ install လုပ္ထားေသာ root directory ၏ path အျပည့္အစုံကုိ ေပးပါသည္။ - $path = config_path(); +### public_path - -#### `database_path()` {#collection-method} +`public` directory ၏ path အျပည့္အစုံကုိ ေပးပါသည္။ -The `database_path` function returns the fully qualified path to the application's database directory: +### storage_path - $path = database_path(); - - -#### `elixir()` {#collection-method} - -The `elixir` function gets the path to a [versioned Elixir file](/docs/{{version}}/elixir): - - elixir($file); - - -#### `public_path()` {#collection-method} - -The `public_path` function returns the fully qualified path to the `public` directory: - - $path = public_path(); - - -#### `resource_path()` {#collection-method} - -The `resource_path` function returns the fully qualified path to the `resources` directory. You may also use the `resource_path` function to generate a fully qualified path to a given file relative to the storage directory: - - $path = resource_path(); - - $path = resource_path('assets/sass/app.scss'); - - -#### `storage_path()` {#collection-method} - -The `storage_path` function returns the fully qualified path to the `storage` directory. You may also use the `storage_path` function to generate a fully qualified path to a given file relative to the storage directory: - - $path = storage_path(); - - $path = storage_path('app/file.txt'); +`app/storage` directory ၏ path အျပည့္အစုံကုိ ေပးပါသည္။ ## Strings - -#### `camel_case()` {#collection-method} - -The `camel_case` function converts the given string to `camelCase`: - - $camel = camel_case('foo_bar'); - - // fooBar - - -#### `class_basename()` {#collection-method} - -The `class_basename` returns the class name of the given class with the class' namespace removed: - - $class = class_basename('Foo\Bar\Baz'); - - // Baz - - -#### `e()` {#collection-method} - -The `e` function runs `htmlentities` over the given string: - - echo e('foo'); - - // <html>foo</html> - - -#### `ends_with()` {#collection-method} - -The `ends_with` function determines if the given string ends with the given value: - - $value = ends_with('This is my name', 'name'); - - // true - - -#### `snake_case()` {#collection-method} - -The `snake_case` function converts the given string to `snake_case`: - - $snake = snake_case('fooBar'); - - // foo_bar - - -#### `str_limit()` {#collection-method} - -The `str_limit` function limits the number of characters in a string. The function accepts a string as its first argument and the maximum number of resulting characters as its second argument: - - $value = str_limit('The PHP framework for web artisans.', 7); +### camel_case - // The PHP... +ေပးထားေသာ string အား `camelCase` ေရးဟန္သုိ့ ေျပာင္းလဲေပးပါသည္။ - -#### `starts_with()` {#collection-method} + $camel = camel_case('foo_bar'); -The `starts_with` function determines if the given string begins with the given value: + // fooBar - $value = starts_with('This is my name', 'This'); +### class_basename - // true +ေပးထားေသာ class ၏ အမည္ကုိ namespace အမည္မ်ား မပါ၀င္ပဲ ေပးပါသည္။ - -#### `str_contains()` {#collection-method} + $class = class_basename('Foo\Bar\Baz'); -The `str_contains` function determines if the given string contains the given value: + // Baz - $value = str_contains('This is my name', 'my'); +### e - // true +`htmlentities` function အား ေပးထားေသာ string ျဖင့္ run ပါသည္။ UTF-8 support ပါ၀င္ပါသည္။ - -#### `str_finish()` {#collection-method} + $entities = e('foo'); -The `str_finish` function adds a single instance of the given value to a string: +### ends_with - $string = str_finish('this/string', '/'); +ပထမ argument တြင္ ေပးထားေသာ string တစ္ခုသည္ ေပးထားေသာ string နွင့္ အဆုံးသတ္ျခင္းရွိမရွိ ဆုံးျဖတ္ေပးပါသည္။ - // this/string/ + $value = ends_with('This is my name', 'name'); - -#### `str_is()` {#collection-method} +### snake_case -The `str_is` function determines if a given string matches a given pattern. Asterisks may be used to indicate wildcards: +ေပးထားေသာ string အား `snake_case` ေရးဟန္ သုိ့ ေျပာင္းလဲေပးပါသည္။ - $value = str_is('foo*', 'foobar'); + $snake = snake_case('fooBar'); - // true + // foo_bar - $value = str_is('baz*', 'foobar'); +### str_limit - // false +string တစ္ခု အတြင္းရွိ အကၡရာအေရအတြက္ကုိ ကန့္သတ္ေပးပါသည္။ - -#### `str_plural()` {#collection-method} + str_limit($value, $limit = 100, $end = '...') -The `str_plural` function converts a string to its plural form. This function currently only supports the English language: +ဥပမာ - $plural = str_plural('car'); + $value = str_limit('The PHP framework for web artisans.', 7); - // cars + // The PHP... - $plural = str_plural('child'); +### starts_with - // children +ပထမ argument တြင္ ေပးထားေသာ string တစ္ခုသည္ ေပးထားေသာ string နွင့္ စတင္ျခင္းရွိမရွိ ဆုံးျဖတ္ေပးပါသည္။ -You may provide an integer as a second argument to the function to retrieve the singular or plural form of the string: + $value = starts_with('This is my name', 'This'); - $plural = str_plural('child', 2); +### str_contains - // children +ပထမ argument တြင္ ေပးထားေသာ string တြင္ ေပးထားေသာ string ပါ၀င္ျခင္းရွိမရွိ ဆုံးျဖတ္ေပးပါသည္။ - $plural = str_plural('child', 1); + $value = str_contains('This is my name', 'my'); - // child +### str_finish - -#### `str_random()` {#collection-method} +ပထမ argument တြင္ေပးထားေသာ string ၏ အဆုံးတြင္ ေပးထားေသာ string အားေပါင္းထည့္ေပးပါသည္။ -The `str_random` function generates a random string of the specified length. This function uses PHP's `random_bytes` function: + $string = str_finish('this/string', '/'); - $string = str_random(40); + // this/string/ - -#### `str_singular()` {#collection-method} +### str_is -The `str_singular` function converts a string to its singular form. This function currently only supports the English language: +ေပးထားေသာ pattern တစ္ခုသည္ ေပးထားေသာ string နွင့္ ကုိက္ညီ မကုိက္ညီ ဆုံးျဖတ္ေပးပါသည္။ ခေရပြင့္အကၡရာ "*" မ်ားအား wildcard အကၡရာအျဖစ္သုံးနုိင္ပါသည္။ - $singular = str_singular('cars'); + $value = str_is('foo*', 'foobar'); - // car +### str_plural - -#### `str_slug()` {#collection-method} +ေပးထားေသာ string တစ္ခုအား English ဘာသာ ျဖင့္ အမ်ားကိန္း (plural) ပုံစံသုိ့ ေျပာင္းလဲေပးပါသည္။ -The `str_slug` function generates a URL friendly "slug" from the given string: + $plural = str_plural('car'); - $title = str_slug('Laravel 5 Framework', '-'); +### str_random - // laravel-5-framework +ေပးထားေသာ အေရအတြက္အတုိင္း အတိအက် ရွိသည့္ က်ပန္း string တစ္ခုကုိ ထုတ္ေပးပါသည္။ - -#### `studly_case()` {#collection-method} + $string = str_random(40); -The `studly_case` function converts the given string to `StudlyCase`: +### str_singular - $value = studly_case('foo_bar'); +ေပးထားေသာ string တစ္ခုအား English ဘာသာ ျဖင့္ အနည္းကိန္း (singular) ပုံစံသုိ့ ေျပာင္းလဲေပးပါသည္။ - // FooBar + $singular = str_singular('cars'); - -#### `title_case()` {#collection-method} +### studly_case -The `title_case` function converts the given string to `Title Case`: +ေပးထားေသာ string အား `StudlyCase` ေရးဟန္သုိ့ ေျပာင္းလဲေပးပါသည္။ - $title = title_case('a nice title uses the correct case'); + $value = studly_case('foo_bar'); - // A Nice Title Uses The Correct Case + // FooBar - -#### `trans()` {#collection-method} +### trans -The `trans` function translates the given language line using your [localization files](/docs/{{version}}/localization): +ေပးထားေသာ string တစ္ေျကာင္းအား ဘာသာျပန္ေပးပါသည္။ `Lang::get` method ၏ အမည္ေျပာင္း method တစ္ခုျဖစ္ပါသည္။ - echo trans('validation.required'): + $value = trans('validation.required'): - -#### `trans_choice()` {#collection-method} +### trans_choice -The `trans_choice` function translates the given language line with inflection: +ေပးထားေသာ string တစ္ေျကာင္းအား ေပးထားေသာ နံပါတ္ အလုိက္ ဘာသာျပန္ message ကုိ အသုံးျပု၍ ဘာသာျပန္ေပးပါသည္။ `Lang::choice` method ၏ အမည္ေျပာင္း method တစ္ခုျဖစ္ပါသည္။ - $value = trans_choice('foo.bar', $count); + $value = trans_choice('foo.bar', $count); ## URLs - -#### `action()` {#collection-method} +### action -The `action` function generates a URL for the given controller action. You do not need to pass the full namespace to the controller. Instead, pass the controller class name relative to the `App\Http\Controllers` namespace: +ေပးထားေသာ controller action တစ္စုံအတြက္ URL တစ္ခု ထုတ္ေပးပါသည္။ - $url = action('HomeController@getIndex'); + $url = action('HomeController@getIndex', $params); -If the method accepts route parameters, you may pass them as the second argument to the method: +### route - $url = action('UserController@profile', ['id' => 1]); +ေပးထားေသာ အမည္ရွိ လမ္းေျကာင္း တစ္ခုအတြက္ URL တစ္ခု ထုတ္ေပးပါသည္။ - -#### `asset()` {#collection-method} + $url = route('routeName', $params); -Generate a URL for an asset using the current scheme of the request (HTTP or HTTPS): +### asset - $url = asset('img/photo.jpg'); - - -#### `secure_asset()` {#collection-method} - -Generate a URL for an asset using HTTPS: - - echo secure_asset('foo/bar.zip', $title, $attributes = []); - - -#### `route()` {#collection-method} - -The `route` function generates a URL for the given named route: - - $url = route('routeName'); - -If the route accepts parameters, you may pass them as the second argument to the method: - - $url = route('routeName', ['id' => 1]); - - -#### `url()` {#collection-method} - -The `url` function generates a fully qualified URL to the given path: - - echo url('user/profile'); - - echo url('user/profile', [1]); - -If no path is provided, a `Illuminate\Routing\UrlGenerator` instance is returned: - - echo url()->current(); - echo url()->full(); - echo url()->previous(); - - -## Miscellaneous - - -#### `abort()` {#collection-method} - -The `abort` function throws a HTTP exception which will be rendered by the exception handler: - - abort(401); - -You may also provide the exception's response text: - - abort(401, 'Unauthorized.'); - - -#### `abort_if()` {#collection-method} - -The `abort_if` function throws an HTTP exception if a given boolean expression evaluates to `true`: - - abort_if(! Auth::user()->isAdmin(), 403); - - -#### `abort_unless()` {#collection-method} - -The `abort_unless` function throws an HTTP exception if a given boolean expression evaluates to `false`: - - abort_unless(Auth::user()->isAdmin(), 403); - - -#### `auth()` {#collection-method} - -The `auth` function returns an authenticator instance. You may use it instead of the `Auth` facade for convenience: - - $user = auth()->user(); - - -#### `back()` {#collection-method} - -The `back()` function generates a redirect response to the user's previous location: - - return back(); - - -#### `bcrypt()` {#collection-method} +ေပးထားေသာ asset အတြက္ URL တစ္ခု ထုတ္ေပးပါသည္။ -The `bcrypt` function hashes the given value using Bcrypt. You may use it as an alternative to the `Hash` facade: - - $password = bcrypt('my-secret-password'); - - -#### `collect()` {#collection-method} - -The `collect` function creates a [collection](/docs/{{version}}/collections) instance from the given array: - - $collection = collect(['taylor', 'abigail']); - - -#### `config()` {#collection-method} - -The `config` function gets the value of a configuration variable. The configuration values may be accessed using "dot" syntax, which includes the name of the file and the option you wish to access. A default value may be specified and is returned if the configuration option does not exist: - - $value = config('app.timezone'); - - $value = config('app.timezone', $default); - -The `config` helper may also be used to set configuration variables at runtime by passing an array of key / value pairs: - - config(['app.debug' => true]); - - -#### `csrf_field()` {#collection-method} - -The `csrf_field` function generates an HTML `hidden` input field containing the value of the CSRF token. For example, using [Blade syntax](/docs/{{version}}/blade): - - {{ csrf_field() }} - - -#### `csrf_token()` {#collection-method} - -The `csrf_token` function retrieves the value of the current CSRF token: - - $token = csrf_token(); - - -#### `dd()` {#collection-method} - -The `dd` function dumps the given variable and ends execution of the script: - - dd($value); - -If you do not want to halt the execution of your script, use the `dump` function instead: - - dump($value); - - -#### `dispatch()` {#collection-method} - -The `dispatch` function pushes a new job onto the Laravel [job queue](/docs/{{version}}/queues): - - dispatch(new App\Jobs\SendEmails); - - -#### `env()` {#collection-method} - -The `env` function gets the value of an environment variable or returns a default value: - - $env = env('APP_ENV'); - - // Return a default value if the variable doesn't exist... - $env = env('APP_ENV', 'production'); - - -#### `event()` {#collection-method} - -The `event` function dispatches the given [event](/docs/{{version}}/events) to its listeners: - - event(new UserRegistered($user)); - - -#### `factory()` {#collection-method} - -The `factory` function creates a model factory builder for a given class, name, and amount. It can be used while [testing](/docs/{{version}}/database-testing#writing-factories) or [seeding](/docs/{{version}}/seeding#using-model-factories): + $url = asset('img/photo.jpg'); - $user = factory(App\User::class)->make(); +### link_to - -#### `method_field()` {#collection-method} +ေပးထားေသာ URL အတြက္ HTML link တစ္ခု ထုတ္ေပးပါသည္။ -The `method_field` function generates an HTML `hidden` input field containing the spoofed value of the form's HTTP verb. For example, using [Blade syntax](/docs/{{version}}/blade): + echo link_to('foo/bar', $title, $attributes = array(), $secure = null); -
    - {{ method_field('DELETE') }} -
    +### link_to_asset - -#### `old()` {#collection-method} +ေပးထားေသာ asset အတြက္ HTML link တစ္ခု ထုတ္ေပးပါသည္။ -The `old` function [retrieves](/docs/{{version}}/requests#retrieving-input) an old input value flashed into the session: + echo link_to_asset('foo/bar.zip', $title, $attributes = array(), $secure = null); - $value = old('value'); +### link_to_route - $value = old('value', 'default'); +ေပးထားေသာ လမ္းေျကာင္း တစ္ခု အတြက္ HTML link တစ္ခု ထုတ္ေပးပါသည္။ - -#### `redirect()` {#collection-method} + echo link_to_route('route.name', $title, $parameters = array(), $attributes = array()); -The `redirect` function returns a redirect HTTP response, or returns the redirector instance if called with no arguments: +### link_to_action - return redirect('/home'); +ေပးထားေသာ controller action တစ္စုံအတြက္ HTML link တစ္ခု ထုတ္ေပးပါသည္။ - return redirect()->route('route.name'); + echo link_to_action('HomeController@getIndex', $title, $parameters = array(), $attributes = array()); - -#### `request()` {#collection-method} +### secure_asset -The `request` function returns the current [request](/docs/{{version}}/requests) instance or obtains an input item: +ေပးထားေသာ asset အတြက္ HTTPS သုံးထားေသာ HTML link တစ္ခု ထုတ္ေပးပါသည္။ - $request = request(); + echo secure_asset('foo/bar.zip', $title, $attributes = array()); - $value = request('key', $default = null) +### secure_url - -#### `response()` {#collection-method} +ေပးထားေသာ path တစ္ခု အတြက္ URL အျပည့္အစုံ တစ္ခု ထုတ္ေပးပါသည္။ -The `response` function creates a [response](/docs/{{version}}/responses) instance or obtains an instance of the response factory: + echo secure_url('foo/bar', $parameters = array()); - return response('Hello World', 200, $headers); +### url - return response()->json(['foo' => 'bar'], 200, $headers); +ေပးထားေသာ path တစ္ခု အတြက္ URL အျပည့္အစုံ ထုတ္ေပးပါသည္။ - -#### `session()` {#collection-method} + echo url('foo/bar', $parameters = array(), $secure = null); -The `session` function may be used to get or set session values: + +## Miscellaneous - $value = session('key'); +### csrf_token -You may set values by passing an array of key / value pairs to the function: +လက္ရွိ CSRF token တန္ဖုိးကုိ ေပးပါသည္။ - session(['chairs' => 7, 'instruments' => 3]); + $token = csrf_token(); -The session store will be returned if no value is passed to the function: +### dd - $value = session()->get('key'); +ေပးထားေသာ variable ကုိ dump လုပ္၍ script execution ကုိ ရပ္ေစပါသည္။ - session()->put('key', $value); + dd($value); - -#### `value()` {#collection-method} +### value -The `value` function's behavior will simply return the value it is given. However, if you pass a `Closure` to the function, the `Closure` will be executed then its result will be returned: +ေပးထားေသာ တန္ဖုိးသည္ `Closure` တစ္ခု ျဖစ္ပါက `Closure` မွတစ္ဆင့္ return ျပန္လာေသာ value ကုိ return ျပန္ေပး၍ `Closure` မဟုတ္ပါက တန္ဖုိးအတုိင္း return ျပန္ေပးပါသည္။ - $value = value(function() { return 'bar'; }); + $value = value(function() { return 'bar'; }); - -#### `view()` {#collection-method} +### with -The `view` function retrieves a [view](/docs/{{version}}/views) instance: +ေပးထားေသာ object ကုိ return ျပန္ေပးပါသည္။ PHP 5.3.x တြင္ method chaining constructor မ်ား အတြက္ အသုံး၀င္ပါသည္။ - return view('auth.login'); + $value = with(new Foo)->doWork(); \ No newline at end of file diff --git a/homestead.md b/homestead.md index dd2207f..7858c48 100644 --- a/homestead.md +++ b/homestead.md @@ -1,260 +1,128 @@ -# Laravel Homestead +# Laravel ရဲ့ Official Development Homestead အကြောင်း -- [Introduction](#introduction) +- [Homestead မိတ်ဆက်](#introduction) +- [Homestead မှာပါဝင်သော Software များ](#included-software) - [Installation & Setup](#installation-and-setup) - - [First Steps](#first-steps) - - [Configuring Homestead](#configuring-homestead) - - [Launching The Vagrant Box](#launching-the-vagrant-box) - - [Per Project Installation](#per-project-installation) - - [Installing MariaDB](#installing-mariadb) -- [Daily Usage](#daily-usage) - - [Accessing Homestead Globally](#accessing-homestead-globally) - - [Connecting Via SSH](#connecting-via-ssh) - - [Connecting To Databases](#connecting-to-databases) - - [Adding Additional Sites](#adding-additional-sites) - - [Configuring Cron Schedules](#configuring-cron-schedules) - - [Ports](#ports) -- [Network Interfaces](#network-interfaces) +- [နေ့စဉ်အသုံးပြုမှူ](#general-usage) +- [Ports](#ports) -## Introduction +## Homestead မိတ်ဆက် -Laravel strives to make the entire PHP development experience delightful, including your local development environment. [Vagrant](http://vagrantup.com) provides a simple, elegant way to manage and provision Virtual Machines. +သင့်ရဲ့ PHP Development environment ကို local development environment မှာပါ ကြည်နူးသာယာဖွယ်ကောင်းအောင်Laravel က အကောင်းဆုံးကြိုးစားအားထုတ်မှူတစ်ခုလုပ်ခဲ့ပါတယ်။ [Vagrant](http://vagrantup.com) ကသင့်ရဲ့ Virtual Machine တွေကို လွယ်လွယ်ကူကူ ထိန်းသိမ်း နိုင်အောင် သင့်ကိုထောက်ပံ့ ပေးထားပါတယ်။ -Laravel Homestead is an official, pre-packaged Vagrant box that provides you a wonderful development environment without requiring you to install PHP, HHVM, a web server, and any other server software on your local machine. No more worrying about messing up your operating system! Vagrant boxes are completely disposable. If something goes wrong, you can destroy and re-create the box in minutes! -Homestead runs on any Windows, Mac, or Linux system, and includes the Nginx web server, PHP 7.0, MySQL, Postgres, Redis, Memcached, Node, and all of the other goodies you need to develop amazing Laravel applications. +Laravel Homestead က official ပါ၊ Vagrant "box" မှာ ကြိုု ပြီး package လုပ်ထားတာပါ... နောက် အဲဒါကသင့်ကို development environment တစ်ခု တည်ဆောက်တဲ့နေရာမှာ PHP, a web server, နဲ့ အခြားအသုံးဝင်တဲ့ tools တွေကို သင့်ရဲ့ local machine မှာ install လုပ်စရာမလိုပါဘူး။ ဘယ် Opearting System ကိုသုံးတယ်ဆိုတာကိုလည်း worry များစရာမလိုတော့ပါဘူး။ Vagrant boxes တွေနဲ့ဘဲ အသုံးပြုလို့ရပါတယ်။ တကယ်လို့တစ်ခုခုမှားသွားတယ်ဆိုရင် vagrant boxes တွေကိုမိနစ်အနည်းငယ်အတွင်း destory လုပ်ပြီးတော့ ပြန်ပြီး create လုပ်နိုင်ပါတယ်။ -> {note} If you are using Windows, you may need to enable hardware virtualization (VT-x). It can usually be enabled via your BIOS. If you are using Hyper-V on a UEFI system you may additionally need to disable Hyper-V in order to access VT-x. +Homestead က မည်သည့် Window, Mac, Linux မှာမဆို run ပါတယ်။ Homesead မှာ Nginx web server, PHP 5.5, MySQL, Postgres, Redis, Memcached နဲ့ အခြား Laravel application အတွက် အသုံးဝင်တာတွေပါဝင်ပါတယ်။ -### Included Software +## Homestead မှာပါဝင်သော Software များ -- Ubuntu 16.04 -- Git -- PHP 7.0 -- HHVM +- Ubuntu 14.04 +- PHP 5.5 - Nginx - MySQL -- MariaDB -- Sqlite3 - Postgres -- Composer -- Node (With PM2, Bower, Grunt, and Gulp) +- Node (With Bower, Grunt, and Gulp) - Redis - Memcached - Beanstalkd +- [Laravel Envoy](ssh#envoy-task-runner.md) +- Fabric + HipChat Extension ## Installation & Setup - -### First Steps +### VirtualBox နဲ့ Vagrant Installing -Before launching your Homestead environment, you must install [VirtualBox 5.x](https://www.virtualbox.org/wiki/Downloads) or [VMWare](http://www.vmware.com) as well as [Vagrant](http://www.vagrantup.com/downloads.html). All of these software packages provide easy-to-use visual installers for all popular operating systems. +သင်အနေနဲ့ Homestead environment ကိုမဖွင့်ခင် [VirtualBox](https://www.virtualbox.org/wiki/Downloads) နဲ့ [Vagrant](http://www.vagrantup.com/downloads.html) ကို install လုပ်ထားရပါ့မယ်။ ဒီ software နှစ်ခုပေါင်းပြီး popular operating systems များကိုလွယ်ကူစွာ virtual install လုပ်လို့ရပါမည်။ -To use the VMware provider, you will need to purchase both VMware Fusion / Workstation and the [VMware Vagrant plug-in](http://www.vagrantup.com/vmware). Though it is not free, VMware can provide faster shared folder performance out of the box. +### Vagrant Box များထည့်ခြင်း -#### Installing The Homestead Vagrant Box +VirtualBox နဲ့ Vagrant ကို install လုပ်ပြီးပြီဆိုရင် ပထမဆုံး သင့်ရဲ့ Vagrant installation မှာ `laravel/homestead` လို့ terminal ကနေ run ပြီး Laravel ရဲ့ Homestead ကို Virtual Box မှာ add လိုက်ပါ။ Laravel ရဲ့ Homestead box ကို download လုပ်ဖို့အတွက် သင့်အင်တာနက် conn ပေါ်မူတည်ပြီး အချိကြာပါ့မယ် -Once VirtualBox / VMware and Vagrant have been installed, you should add the `laravel/homestead` box to your Vagrant installation using the following command in your terminal. It will take a few minutes to download the box, depending on your Internet connection speed: + vagrant box add laravel/homestead - vagrant box add laravel/homestead +### Clone The Homestead Repository -If this command fails, make sure your Vagrant installation is up to date. +သင်ရဲ့ Vagrant Installation မှာ box ထည့်ပြီးသွားပြီဆိုရင် သင့်အနေနဲ့ဒီ repository ကို download ဒါမှမဟုတ် clone လုပ်ပေးပါ။ နားလည်ထားရမှာက ဒီ repositiry က `Homestead` ပါ၊ ဒီ Folder ထဲမှာ သင့်ရဲ့ Laravel Projects တွေကို ထားရမှာပါ၊ Homestead box တွေကသင့်ရဲ့ Laravel (နဲ့ PHP Projects) တွေကို host အဖြစ် run မှာဖြစ်ပါတယ်။ -#### Installing Homestead + git clone https://github.com/laravel/homestead.git Homestead -You may install Homestead by simply cloning the repository. Consider cloning the repository into a `Homestead` folder within your "home" directory, as the Homestead box will serve as the host to all of your Laravel projects: +### Set Your SSH Key - cd ~ +ပြီးရင်တော့သင် download လုပ်ထားတဲ့ repository ထဲမှာပါတဲ့ `Homestead.yaml` file ကို edit လုပ်သင့်ပါတယ်။ ဒီ file ထဲမှာဆိုရင် သင်ရဲ့ public SSH key တို့ နောက် သင့်ရဲ့ main machine နဲ့ Homestead virtual machine တို့ကို share တဲ့ Folder တို့ကို configure လုပ်နိုင်ပါတယ်။ - git clone https://github.com/laravel/homestead.git Homestead +သင့်မှာ SSH key မရှိဘူးလား၊ သင်က Linux ဒါမှမဟုတ် Mac မှာဆိုရင် အောက်မှာဖော်ပြထားတဲ့ command ကို run လိုက်တာနဲ့ ssh key တစ်စုံကိုသင့်အတွက်ဖန်တီးပေးပါလိမ့်မယ် -Once you have cloned the Homestead repository, run the `bash init.sh` command from the Homestead directory to create the `Homestead.yaml` configuration file. The `Homestead.yaml` file will be placed in the `~/.homestead` hidden directory: + ssh-keygen -t rsa -C "your@email.com" - bash init.sh +Windows မှာဆိုရင် သင်အနေနဲ့ [Git](http://git-scm.com/) ကို install လုပ်ပြီးတော့ `Git Bash`မှာ အထက်က command ကို run ပြီးတော့ အဆင်ပြေပါတယ်။ အဲလိုမှမဟုတ်ဘူးဆိုရင်လည်း[PuTTY](http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html) and [PuTTYgen](http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html). တို့ကိုအသုံးပြုနိုင်ပါတယ်။ - -### Configuring Homestead +သင် SSH Key ကို create လုပ်ပြီးပြီဆိုရင် `Homestead.yaml` file ထဲက `authorize` ဆိုတဲ့ လမ်းကြောင်းထဲမှာ သင့်ရဲ့ SSH Key ရဲ့ path ကိုသတ်မှတ်လိုက်ပါ။ -#### Setting Your Provider +### Configure Your Shared Folders -The `provider` key in your `~/.homestead/Homestead.yaml` file indicates which Vagrant provider should be used: `virtualbox`, `vmware_fusion`, or `vmware_workstation`. You may set this to the provider you prefer: +သင့်ရဲ့ Homestead environment နဲ့ သင့်ရဲ့ local machine နှစ်ခုကြားမှာ Share တဲ့ Folder တွေအားလုံးက `Homestead.yaml` File ထဲမှာရှိမှာပါ။ တကယ်လို့ အဲ့ဒီ့ Files တွေ change သွားရင် သင့်ရဲ့ local machine နဲ့ Homestead environment ကို auto sync လုပ်ပေးသွားမှာပါ။ Share Folders တွေအများကြီးကိုလည်းသင်လိုအပ်ရင် configure လုပ်ရမှာပါ။ - provider: virtualbox +### Configure Your Nginx Sites -#### Configuring Shared Folders +Nginx နဲ့သိပ်မရင်းနှီးဘူးမဟုတ်လား ပြသနာမရှိပါဘူး။ `sites` တွေကသင့်ရဲ့ Homestead environment က Folders တွေကို "domain" ဆီကိုလွယ်ကူစွာ map ပေးပါလိမ့်မယ်။ Site configuration တစ်ခုကို `Homestead.yaml` မှာတွေ့နိုင်ပါတယ်။ သင့်အနေနဲ့ sites အများကြီးကိုသင့်ရဲ့ Homestead မှာထည့်ချင်ပါလိမ့်မယ်၊ Homestad က သင့်virtualized Laravel Projects တွေရဲ့ environment တွေကို အဆင်ပြေစေပါလိမ့်မယ်။ -The `folders` property of the `Homestead.yaml` file lists all of the folders you wish to share with your Homestead environment. As files within these folders are changed, they will be kept in sync between your local machine and the Homestead environment. You may configure as many shared folders as necessary: +### Bash Aliases - folders: - - map: ~/Code - to: /home/vagrant/Code +To add Bash aliases to your Homestead box, simply add to the `aliases` file in the root of the Homestead directory. -To enable [NFS](http://docs.vagrantup.com/v2/synced-folders/nfs.html), just add a simple flag to your synced folder configuration: +### VagrantBox ကိုစတင်ခြင်း - folders: - - map: ~/Code - to: /home/vagrant/Code - type: "nfs" +`Homestead.yaml` file မှာသင့်ရဲ့ link တွေကို edit လုပ်ပြီးပြီဆိုရင် သင့်ရဲ့ `Homestead` directory ထဲမှာ `vagrant up` ဆိုပြီး terminal ကနေ run လိုက်ပါ။ Vagrant က Virtual Machine ကို boot လုပ်ပါ့လိမ့်မယ် ပြီးရင်တော့ သင့်ရဲ့ share folders နဲ့ Nginx sites တွေကို auto configure လုပ်သွားပါလိမ့်မယ်။ -#### Configuring Nginx Sites +သင့်ရဲ့ Nginx sites တွေအတွက် "domain" တွေကို သင်ရဲ့ local machine က hosts မှာထက်ပေါင်းထည့်ဖို့မမေ့ပါနဲ့ဦး။ hosts file ကသင့် local machine က requests တွေကို Homestead ဆီကို redirect လုပ်ပေးပါလိမ့်မယ်။ Mac နဲ့ linux မှာ ဆိုရင် hosts file က `/etc/hosts` ထဲမှာပြင်လို့ရပါတယ်။ Window မှာဆိုရင်တော့ `C:\Windows\System32\drivers\etc\hosts` မှာရှိပါတယ်။ သင်ထက်ပေါင်းထည့်ရမယ့် line က အောက်ကလိုဖြစ်ပါလိမ့်မယ်၊ -Not familiar with Nginx? No problem. The `sites` property allows you to easily map a "domain" to a folder on your Homestead environment. A sample site configuration is included in the `Homestead.yaml` file. Again, you may add as many sites to your Homestead environment as necessary. Homestead can serve as a convenient, virtualized environment for every Laravel project you are working on: + 127.0.0.1 homestead.app - sites: - - map: homestead.app - to: /home/vagrant/Code/Laravel/public +သင့်ရဲ့ domain ကိုသင့်ရဲ့ `hosts` file ထဲကိုပေါင်းထည့်ပြီးပြီဆိုရင် သင်ရဲ့ browser ကနေသင့် domain နောက်က port နံပါတ်နဲ့ဆိုရင်သင့်ရဲ့ဆိုက်ကို access လုပ်လို့ရပါပြီ။ -You can make any Homestead site use [HHVM](http://hhvm.com) by setting the `hhvm` option to `true`: + http://homestead.app:8000 - sites: - - map: homestead.app - to: /home/vagrant/Code/Laravel/public - hhvm: true - -If you change the `sites` property after provisioning the Homestead box, you should re-run `vagrant reload --provision` to update the Nginx configuration on the virtual machine. - -#### The Hosts File - -You must add the "domains" for your Nginx sites to the `hosts` file on your machine. The `hosts` file will redirect requests for your Homestead sites into your Homestead machine. On Mac and Linux, this file is located at `/etc/hosts`. On Windows, it is located at `C:\Windows\System32\drivers\etc\hosts`. The lines you add to this file will look like the following: - - 192.168.10.10 homestead.app - -Make sure the IP address listed is the one set in your `~/.homestead/Homestead.yaml` file. Once you have added the domain to your `hosts` file and launched the Vagrant box you will be able to access the site via your web browser: - - http://homestead.app - - -### Launching The Vagrant Box - -Once you have edited the `Homestead.yaml` to your liking, run the `vagrant up` command from your Homestead directory. Vagrant will boot the virtual machine and automatically configure your shared folders and Nginx sites. - -To destroy the machine, you may use the `vagrant destroy --force` command. - - -### Per Project Installation - -Instead of installing Homestead globally and sharing the same Homestead box across all of your projects, you may instead configure a Homestead instance for each project you manage. Installing Homestead per project may be beneficial if you wish to ship a `Vagrantfile` with your project, allowing others working on the project to simply `vagrant up`. - -To install Homestead directly into your project, require it using Composer: - - composer require laravel/homestead --dev - -Once Homestead has been installed, use the `make` command to generate the `Vagrantfile` and `Homestead.yaml` file in your project root. The `make` command will automatically configure the `sites` and `folders` directives in the `Homestead.yaml` file. - -Mac / Linux: - - php vendor/bin/homestead make - -Windows: - - vendor\\bin\\homestead make - -Next, run the `vagrant up` command in your terminal and access your project at `http://homestead.app` in your browser. Remember, you will still need to add an `/etc/hosts` file entry for `homestead.app` or the domain of your choice. - - -### Installing MariaDB - -If you prefer to use MariaDB instead of MySQL, you may add the `mariadb` option to your `Homestead.yaml` file. This option will remove MySQL and install MariaDB. MariaDB serves as a drop-in replacement for MySQL so you should still use the `mysql` database driver in your application's database configuration: - - box: laravel/homestead - ip: "192.168.20.20" - memory: 2048 - cpus: 4 - provider: virtualbox - mariadb: true +သင်ရဲ့ database တွေကိုဘယ်လို connect လုပ်မလဲဆိုတာကို လေ့လာဖို့ ဆက်ဖတ်ပါဦ။ -## Daily Usage - - -### Accessing Homestead Globally - -Sometimes you may want to `vagrant up` your Homestead machine from anywhere on your filesystem. You can do this by adding a simple Bash function to your Bash profile. This function will allow you to run any Vagrant command from anywhere on your system and will automatically point that command to your Homestead installation: +## နေ့စဉ်အသုံးပြုမှူ - function homestead() { - ( cd ~/Homestead && vagrant $* ) - } +### SSH ကို connect လုပ်ခြင်း -Make sure to tweak the `~/Homestead` path in the function to the location of your actual Homestead installation. Once the function is installed, you may run commands like `homestead up` or `homestead ssh` from anywhere on your system. +သင့်ရဲ့ Homestead environment ကို SSH ကနေ ချိတ်ဆက်ဝင်ဖို့ သင့်အနေနဲ့ `127.0.0.1` port ကတော့ 2222 ဖြစ်ပြီး SSH key ကတော့ သင်ရဲ့`Homestead.yaml`မှာ သင်သတ်မှတ်ခဲ့တဲ့ key ဘဲဖြစ်ပါတယ်။ `vagrant ssh` ဆိုပြီးသင့်ရဲ့ Homestead Folder ကနေလည်း ဝင်လို့ရပါတယ်။ - -### Connecting Via SSH +သင်အနေနဲ့ ဒါ့ထက်အဆင်ပြေမှူ လိုချင်သေးတယ်ဆိုရင်တော့ အောက်မှာဖော်ပြထားတဲ့ alias ကို သင့်ရဲ့ `~/.bash_aliases` ဒါမှမဟုတ် `~/.bash_profile` မှာပေါင်းထည့်လိုက်တာက ပိုပြီးအသုံးဝင်ပါမယ်၊ -You can SSH into your virtual machine by issuing the `vagrant ssh` terminal command from your Homestead directory. + alias vm='ssh vagrant@127.0.0.1 -p 2222' -But, since you will probably need to SSH into your Homestead machine frequently, consider adding the "function" described above to your host machine to quickly SSH into the Homestead box. +### သင့်ရဲ့ Databases များကို connect လုပ်ခြင်း - -### Connecting To Databases +homestead` ရဲ့ databases တွေဖြစ်တဲ့ MySQL နဲ့ Postgres နှစ်ခုလုံးကို box တွေရဲ့အပြင်မှာ configuration လုပ်ထားပါတယ်။ ဒါထက်ပိုပြီးအဆင်ပြေဖို့ Laravel ရဲ့ `local` database ကို default configure လုပ်ထားပါတယ်။ -A `homestead` database is configured for both MySQL and Postgres out of the box. For even more convenience, Laravel's `.env` file configures the framework to use this database out of the box. +သင့်ရဲ့ database MySQL ဒါမှမဟုတ် Postgres ကို Navicat (သို့) Sequel Pro ကနေသင့်ရဲ့ main machine နဲ့ connect လုပ်ချင်တယ်ဆိုရင် သင့်အနေနဲ့ MySQL အတွက် `127.0.0.1` နဲ့ port 33060 နဲ့Postgres အတွက် port 54320 ဖြစ်ပါတယ်။ Database နှစ်ခုလုံးအတွက် username နဲ့ password က `homestead`/ `secreat` ဖြစ်ပါတယ်။ -To connect to your MySQL or Postgres database from your host machine via Navicat or Sequel Pro, you should connect to `127.0.0.1` and port `33060` (MySQL) or `54320` (Postgres). The username and password for both databases is `homestead` / `secret`. +> **Note:** You should only use these non-standard ports when connecting to the databases from your main machine. You will use the default 3306 and 5432 ports in your Laravel database configuration file since Laravel is running _within_ the Virtual Machine. -> {note} You should only use these non-standard ports when connecting to the databases from your host machine. You will use the default 3306 and 5432 ports in your Laravel database configuration file since Laravel is running _within_ the virtual machine. +### နောက်ထက်ဆိုက်တစ်ခု ထပ်ထည့်ခြင်း - -### Adding Additional Sites +သင့်ရဲ့ Homestead environment ကသင်ထည့်ချင်တာတွေထည့်ပြီးသွားပြီ run လည်း run နေပြီဆိုရင် သင့်အနေနဲ့ Laravel applications တွေကို သင့်ရဲ့ Nginx sites မှာထပ်ထည့်ချင်မှာပေါ့။ Homestead environment တစ်ခုမှာ သင်ကြိုက်သလောက် Laravel installation လုပ်နိုင်ပါတယ်။ Laravel application ထက်ပေါင်းထည့် တဲ့နေရာမှာ နည်းနှစ်ခုရှိပါတယ်။ ပထမတစ်ခုကသင့်ရဲ့ `Homestead.yaml` files မှာထက်ပေါင်းထည့်ပါ ပြီးရင် `vagrant destory` နဲ့ box တွေကို ဖျက်ပါ၊ ပြီးရင် `vagrant up` ပြန်လုပ်ပါ။ -Once your Homestead environment is provisioned and running, you may want to add additional Nginx sites for your Laravel applications. You can run as many Laravel installations as you wish on a single Homestead environment. To add an additional site, simply add the site to your `~/.homestead/Homestead.yaml` file and then run the `vagrant provision` terminal command from your Homestead directory. +နောက်ထက်နည်းတစ်ခုကတော့ သင့်ရဲ့ Homestead environment မှာ `serve` script ကိုသုံးပြီး Laravel application တွေကိုထက်ထည့်နိုင်ပါတယ်။ `serve` script ကိုအသုံးပြုချင်တယ်ဆိုရင်တော့ သင့်ရဲ့ Homestead environment ထဲကိုဝင်ပြီးတော့ အောက်က command ကို run လိုက်ပါ - -### Configuring Cron Schedules + serve domain.app /home/vagrant/Code/path/to/public/directory -Laravel provides a convenient way to [schedule Cron jobs](/docs/{{version}}/scheduling) by scheduling a single `schedule:run` Artisan command to be run every minute. The `schedule:run` command will examine the job scheduled defined in your `App\Console\Kernel` class to determine which jobs should be run. - -If you would like the `schedule:run` command to be run for a Homestead site, you may set the `schedule` option to `true` when defining the site: - - sites: - - map: homestead.app - to: /home/vagrant/Code/Laravel/public - schedule: true - -The Cron job for the site will be defined in the `/etc/cron.d` folder of the virtual machine. +> **မှတ်ချက်:** `serve` command ကို run ပြီးပြီဆိုရင် `hosts` file ထဲမှာ သင်ထပ်ပေါင်းထည့်လိုက်တဲ့ နောက်ထက် site ကို သင့်ရဲ့ စက်မှာ ထက်ပေါင်းထည့်ဖို့ မမေ့ပါနဲ့။ -### Ports - -By default, the following ports are forwarded to your Homestead environment: - -- **SSH:** 2222 → Forwards To 22 -- **HTTP:** 8000 → Forwards To 80 -- **HTTPS:** 44300 → Forwards To 443 -- **MySQL:** 33060 → Forwards To 3306 -- **Postgres:** 54320 → Forwards To 5432 - -#### Forwarding Additional Ports - -If you wish, you may forward additional ports to the Vagrant box, as well as specify their protocol: - - ports: - - send: 93000 - to: 9300 - - send: 7777 - to: 777 - protocol: udp - - -## Network Interfaces - -The `networks` property of the `Homestead.yaml` configures network interfaces for your Homestead environment. You may configure as many interfaces as necessary: - - networks: - - type: "private_network" - ip: "192.168.10.20" - -To enable a [bridged](https://www.vagrantup.com/docs/networking/public_network.html) interface, configure a `bridge` setting and change the network type to `public_network`: - - networks: - - type: "public_network" - ip: "192.168.10.20" - bridge: "en1: Wi-Fi (AirPort)" +## Ports -To enable [DHCP](https://www.vagrantup.com/docs/networking/public_network.html), just remove the `ip` option from your configuration: +အောက်မှာဖော်ပြထားတဲ့ ports တွေက သင့် Homestead ရဲ့ ports တွေဖြစ်ပါတယ် - networks: - - type: "public_network" - bridge: "en1: Wi-Fi (AirPort)" +- **SSH:** 2222 -> Forwards To 22 +- **HTTP:** 8000 -> Forwards To 80 +- **MySQL:** 33060 -> Forwards To 3306 +- **Postgres:** 54320 -> Forwards To 5432 diff --git a/html.md b/html.md new file mode 100644 index 0000000..c125e0d --- /dev/null +++ b/html.md @@ -0,0 +1,197 @@ +# Forms & HTML + +- [Opening A Form](#opening-a-form) +- [CSRF Protection](#csrf-protection) +- [Form Model Binding](#form-model-binding) +- [Labels](#labels) +- [Text, Text Area, Password & Hidden Fields](#text) +- [Checkboxes and Radio Buttons](#checkboxes-and-radio-buttons) +- [File Input](#file-input) +- [Drop-Down Lists](#drop-down-lists) +- [Buttons](#buttons) +- [Custom Macros](#custom-macros) +- [Generating URLs](#generating-urls) + + +## Opening A Form + +#### Opening A Form + + {{ Form::open(array('url' => 'foo/bar')) }} + // + {{ Form::close() }} + +By default, a `POST` method will be assumed; however, you are free to specify another method: + + echo Form::open(array('url' => 'foo/bar', 'method' => 'put')) + +> **Note:** Since HTML forms only support `POST` and `GET`, `PUT` and `DELETE` methods will be spoofed by automatically adding a `_method` hidden field to your form. + +You may also open forms that point to named routes or controller actions: + + echo Form::open(array('route' => 'route.name')) + + echo Form::open(array('action' => 'Controller@method')) + +You may pass in route parameters as well: + + echo Form::open(array('route' => array('route.name', $user->id))) + + echo Form::open(array('action' => array('Controller@method', $user->id))) + +If your form is going to accept file uploads, add a `files` option to your array: + + echo Form::open(array('url' => 'foo/bar', 'files' => true)) + + +## CSRF Protection + +#### Adding The CSRF Token To A Form + +Laravel provides an easy method of protecting your application from cross-site request forgeries. First, a random token is placed in your user's session. Don't sweat it, this is done automatically. The CSRF token will be added to your forms as a hidden field automatically. However, if you wish to generate the HTML for the hidden field, you may use the `token` method: + + echo Form::token(); + +#### Attaching The CSRF Filter To A Route + + Route::post('profile', array('before' => 'csrf', function() + { + // + })); + + +## Form Model Binding + +#### Opening A Model Form + +Often, you will want to populate a form based on the contents of a model. To do so, use the `Form::model` method: + + echo Form::model($user, array('route' => array('user.update', $user->id))) + +Now, when you generate a form element, like a text input, the model's value matching the field's name will automatically be set as the field value. So, for example, for a text input named `email`, the user model's `email` attribute would be set as the value. However, there's more! If there is an item in the Session flash data matching the input name, that will take precedence over the model's value. So, the priority looks like this: + +1. Session Flash Data (Old Input) +2. Explicitly Passed Value +3. Model Attribute Data + +This allows you to quickly build forms that not only bind to model values, but easily re-populate if there is a validation error on the server! + +> **Note:** When using `Form::model`, be sure to close your form with `Form::close`! + + +## Labels + +#### Generating A Label Element + + echo Form::label('email', 'E-Mail Address'); + +#### Specifying Extra HTML Attributes + + echo Form::label('email', 'E-Mail Address', array('class' => 'awesome')); + +> **Note:** After creating a label, any form element you create with a name matching the label name will automatically receive an ID matching the label name as well. + + +## Text, Text Area, Password & Hidden Fields + +#### Generating A Text Input + + echo Form::text('username'); + +#### Specifying A Default Value + + echo Form::text('email', 'example@gmail.com'); + +> **Note:** The *hidden* and *textarea* methods have the same signature as the *text* method. + +#### Generating A Password Input + + echo Form::password('password'); + +#### Generating Other Inputs + + echo Form::email($name, $value = null, $attributes = array()); + echo Form::file($name, $attributes = array()); + + +## Checkboxes and Radio Buttons + +#### Generating A Checkbox Or Radio Input + + echo Form::checkbox('name', 'value'); + + echo Form::radio('name', 'value'); + +#### Generating A Checkbox Or Radio Input That Is Checked + + echo Form::checkbox('name', 'value', true); + + echo Form::radio('name', 'value', true); + + +## File Input + +#### Generating A File Input + + echo Form::file('image'); + +> **Note:** The form must have been opened with the `files` option set to `true`. + + +## Drop-Down Lists + +#### Generating A Drop-Down List + + echo Form::select('size', array('L' => 'Large', 'S' => 'Small')); + +#### Generating A Drop-Down List With Selected Default + + echo Form::select('size', array('L' => 'Large', 'S' => 'Small'), 'S'); + +#### Generating A Grouped List + + echo Form::select('animal', array( + 'Cats' => array('leopard' => 'Leopard'), + 'Dogs' => array('spaniel' => 'Spaniel'), + )); + +#### Generating A Drop-Down List With A Range + + echo Form::selectRange('number', 10, 20); + +#### Generating A List With Month Names + + echo Form::selectMonth('month'); + + +## Buttons + +#### Generating A Submit Button + + echo Form::submit('Click Me!'); + +> **Note:** Need to create a button element? Try the *button* method. It has the same signature as *submit*. + + +## Custom Macros + +#### Registering A Form Macro + +It's easy to define your own custom Form class helpers called "macros". Here's how it works. First, simply register the macro with a given name and a Closure: + + Form::macro('myField', function() + { + return ''; + }); + +Now you can call your macro using its name: + +#### Calling A Custom Form Macro + + echo Form::myField(); + + + +##Generating URLs + +For more information on generating URL's, check out the documentation on [helpers](helpers#urls.md). diff --git a/installation.md b/installation.md index bec3277..5d2c8a4 100644 --- a/installation.md +++ b/installation.md @@ -1,82 +1,83 @@ -# Installation +# Laravel install လုပ်ခြင်း -- [Installation](#installation) - - [Server Requirements](#server-requirements) - - [Installing Laravel](#installing-laravel) - - [Configuration](#configuration) +- [Composer ကို Install လုပ်ခြင်း](#install-composer) +- [Laravel ကို Install လုပ်ခြင်း](#install-laravel) +- [Server လိုအပ်ချက်မျာ](#server-requirements) +- [Configuration လုပ်ခြင်း](#configuration) +- [URL လှလှလေးလိုချင်တယ်](#pretty-urls) - -## Installation + +## Composer ကို Install လုပ်ခြင်း - -### Server Requirements +Laravel ရဲ့အသုံးဝင်တဲ့tool .... [Composer](http://getcomposer.org), သူ့ရဲ့ depenedencies တွေကို Manage လုပ်ဖို့။ ပထမဆုံး `composer.phar` copy ကိို download လုပ်လိုက်ပါ။ download လုပ်ပြီးသွားပြီဆိုရင် သင့်မှာ PHAR ဆိုတဲ့file လေးရှိသွားပါပြီ၊ အဲဒီ့ file ကိုသင့်ရဲ့local project မှာဒီတိုင်းထားချင်ရင်လည်းရပါတယ် တကယ်လို့သင်က `usr/local/bin` ထဲကိုရွှေ့ပြီးတော့သင့်ရဲ့ System အတွက် Global လုပ်မယ်ဆိုလည်းလုပ်နိုင်ပါတယ်။ Window မှာဆိုရင်တော့ [Windows installer](https://getcomposer.org/Composer-Setup.exe) ကိုသုံးပြီး install လုပ်နိုင်ပါတယ်။ -The Laravel framework has a few system requirements. Of course, all of these requirements are satisfied by the [Laravel Homestead](/docs/{{version}}/homestead) virtual machine, so it's highly recommended that you use Homestead as your local Laravel development environment. + +## Laravel ကို Install လုပ်ခြင်း -However, if you are not using Homestead, you will need to make sure your server meets the following requirements: +### Laravel Installer မှတစ်ဆင့် -
    -- PHP >= 5.6.4 -- OpenSSL PHP Extension -- PDO PHP Extension -- Mbstring PHP Extension -- Tokenizer PHP Extension -
    +ပထမဆုံး[Laravel installer PHAR archive](http://laravel.com/laravel.phar) ကို download လုပ်ပါ၊ install လုပ်ရာမှာလွယ်ကူအောင်လို့ file name ကို `laravel` လို့ပြောင်းလိုက်ပါ၊ ပြောင်းပြီးသွားရင်အဲ့ဒီ့ File ကို `/usr/local/bin` ထဲကိုရွှေ့လိုက်ပါ။ Laravel ကို Install လုပ်မယ်ဆိုရင် `laravel new` ဆိုပြီး command line ကနေ run လိုက်ရင် Laravel Framework တစ်ခုကိုကိုယ်ကြိုက်တဲ့နေရာမှာ Install လုပ်နိုင်ပါပြီ။ `laravel new blog` ဆိုပြီး command line ကနေ run လိုက်ရင် blog ဆိုတဲ့အမည်နဲ့ command line ကနေကိုယ် create လုပ်ချင်တဲ့နေရာမှာ Laravel Framework အသစ်တစ်ခုကို install လုပ်ပေးမှာဖြစ်ပါတယ်။ ဒီနည်းက composer ကနေ download လုပ်တာထက်ပိုမြန်ပါတယ်။ - -### Installing Laravel +သင့်အနေနဲ့ Laravel ကို Composer ကနေတစ်ဆင့် `create-project` command သုံးပြီးတော့လည်း install လုပ်နိုင်ပါတယ်၊ terminal မှာ အောက်မှာရေးထားတဲ့ command ကို run ပြီးတော့လည်း install လုပ်နိုင်ပါတယ် -Laravel utilizes [Composer](http://getcomposer.org) to manage its dependencies. So, before using Laravel, make sure you have Composer installed on your machine. + composer create-project laravel/laravel --prefer-dist -#### Via Laravel Installer +### Download မှတစ်ဆင့် -First, download the Laravel installer using Composer: +Composer ကို install လုပ်ပြီးသွားပြီဆိုရင် Laravel Framework [latest version](https://github.com/laravel/laravel/archive/master.zip) ကို download လုပ်လိုက်ပါ၊ သင့်ရဲ့ web server ထဲမှာ zip ကို extra လုပ်လိုက်ပါ၊ extra လုပ်ထားတဲ့ framework folder ထဲကို command line ကဝင်ပြီးတော့ `php composer.phar install` ဒါမှမဟုတ် (`composer install`) ဆိုပြီး run လိုက်ပါ။ ဒီ command က framework ရဲ့ dependencies တွေကို install လုပ်ခိုင်းလိုက်တာပါ။ ဒီ installation လုပ်တဲ့နေရာမှာ webserver မှာ git install လုပ်ထားမှ successfully complete ဖြစ်မှာပါ။ - composer global require "laravel/installer" +တကယ်လို့သင် Framework ကို update လုပ်ချင်တယ်ဆိုရင်`php composer.phar update` command ကို run ပေးရပါ့မယ်။ -Make sure to place the `~/.composer/vendor/bin` directory (or the equivalent directory for your OS) in your $PATH so the `laravel` executable can be located by your system. + +## Server လိုအပ်ချက်များ +Laravel Framework မှာ system requirements တစ်ချို့ရှိပါတယ်။ ဘာတွေလည်းဆိုရင် -Once installed, the `laravel new` command will create a fresh Laravel installation in the directory you specify. For instance, `laravel new blog` will create a directory named `blog` containing a fresh Laravel installation with all of Laravel's dependencies already installed: +- PHP >= 5.3.7 +- MCrypt PHP Extension - laravel new blog +တို့ဘဲဖြစ်ပါတယ်။ -#### Via Composer Create-Project +PHP 5.5 မှာ တစ်ချို့ OS တွေက PHP JSON extension ကို manullly install လုပ်ပေးရပါတယ်။ တကယ်လို့ Ubuntu သုံးတယ်ဆိုရင် `apt-get install php5-json` ဆိုပြီး terminal ကနေ run လိုက်တာနဲ့အဆင်ပြေပါတယ်။ -Alternatively, you may also install Laravel by issuing the Composer `create-project` command in your terminal: + +## Configuration လုပ်ခြင်း - composer create-project --prefer-dist laravel/laravel blog +Laravel က configuration ဆိုတာမရှိသလောက်ပါဘဲ။ သင်စပြီး develop ဖို့ရာအဆင်သင့်ပါဘဲ။ဘယ်လိုဘဲပြောပြော သင့်အနေနဲ့ `app/config/app.php` file နဲ့သူ့ရဲ့ Documencation ကိုပြန်ကြည့်ချင်မှာပါဘဲ။ `app/config/app.php`မှာဘာတွေပါသလဲဆိုရင်တော့ `timezone` နောက် `locale`တို့ပါပါတယ်၊သင့်ရဲ့ application နဲ့အဆင်ပြေတာတွေကို configure လုပ်နိုင်ပါတယ်။ - -### Configuration +Laravel ကိုတစ်ခါ Install လုပ်တိုင်း [သင့်ရဲ့ local environmet](configuration#environment-configuration.md) ကို Configure ပြန်လုပ်သင့်ပါတယ်။ local machine မှာ develop လုပ်တဲ့အခါ erros ကိုမြင်ရမယ်။ မူလကတော့ error reporting က သင့်ရဲ့ development production မှာ disable လုပ်ထားပါတယ်။ -#### Public Directory +> **မှတ်ချက်:** `app.debug` ကို production မှာဘယ်တော့မှ true မပေးသင့်ပါဘူး။ဘယ်တော့မှ မလုပ်ပါနဲ့။ -After installing Laravel, you should configure your your web server's document / web root to be the `public` directory. The `index.php` in this directory serves as the front controller for all HTTP requests entering your application. + +### Permissions များ -#### Configuration Files +Laravel က `app/storage` ကို web server အတွက် permission write ပေးရပါမယ်။ -All of the configuration files for the Laravel framework are stored in the `config` directory. Each option is documented, so feel free to look through the files and get familiar with the options available to you. + +### လမ်းကြောင်းများ -#### Directory Permissions +Framework ရဲ့ လမ်းကြောင်းတွေကပြောင်းလဲနိုင်ပါတယ်၊ ဒီ location တွေကိုပြောင်းချင်တယ်ဆိုရင် `bootstrap/paths.php` မှာကြည့်ရှူပြောင်းလည်းနိုင်ပါတယ်။ -After installing Laravel, you may need to configure some permissions. Directories within the `storage` and the `bootstrap/cache` directories should be writable by your web server or Laravel will not run. If you are using the [Homestead](/docs/{{version}}/homestead) virtual machine, these permissions should already be set. + +## URL လှလှလေးလိုချင်တယ် -#### Application Key +### Apache -The next thing you should do after installing Laravel is set your application key to a random string. If you installed Laravel via Composer or the Laravel installer, this key has already been set for you by the `php artisan key:generate` command. +Framework ထဲက `public/.htaccess` ကို URL မှာ `index.php` မပါအောင်ဖျောက်ထားပေးမှာဖြစ်ပါတယ်။ တကယ်လို့သင့် ရဲ့ Laravel application က Apache ကိုသုံးတယ်ဆိုရင် `mod_rewrite` ကို enable လုပ်ဖို့မမေ့ပါနဲ့ဦး။ -Typically, this string should be 32 characters long. The key can be set in the `.env` environment file. If you have not renamed the `.env.example` file to `.env`, you should do that now. **If the application key is not set, your user sessions and other encrypted data will not be secure!** +တကယ်လို့ `.htaccess`file က သင့် Application မှာအလုပ်မလုပ်ဘူးဆိုရင် အောက်ကတစ်ခုကိုစမ်းကြည့်လိုက်ပါ: -#### Additional Configuration + Options +FollowSymLinks + RewriteEngine On -Laravel needs almost no other configuration out of the box. You are free to get started developing! However, you may wish to review the `config/app.php` file and its documentation. It contains several options such as `timezone` and `locale` that you may wish to change according to your application. + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] -You may also want to configure a few additional components of Laravel, such as: +### Nginx -
    -- [Cache](/docs/{{version}}/cache#configuration) -- [Database](/docs/{{version}}/database#configuration) -- [Session](/docs/{{version}}/session#configuration) -
    +Nginx မှာဆိုရင်အောက်ကညွှန်ကြားချက်ကို လိုက်လုပ်လိုက်တာနဲ့URL လှလှလေးတွေရပါတယ် -Once Laravel is installed, you should also [configure your local environment](/docs/{{version}}/configuration#environment-configuration). + location / { + try_files $uri $uri/ /index.php?$query_string; + } diff --git a/introduction.md b/introduction.md new file mode 100644 index 0000000..98bbadd --- /dev/null +++ b/introduction.md @@ -0,0 +1,25 @@ +# Laravel Framework မိတ်ဆက် + + - [ဘယ်ကနေစမလဲ](#where-to-start) + - [Laravel သဘောတရား](#laravel-philosophy) + +## ဘယ်ကနေစမလဲ + +Framework အသစ်တစ်ခုကို လေ့လာရတာကိုလန့်နေနိုင်ပါတယ်၊ ဒါပေမယ့် ဒါဟာ ရင်ခုန်ဖို့အရမ်းကောင်းပါတယ်။ သင့်ရဲ့ အကူးအပြောင်းကိုအဆင်ပြေဖို့၊ ကျွန်တော်တို့က ကျစ်လျစ်ပြည့်စုံပြီး အရှင်းဆုံးဖြစ်အောင်ကြိုးပမ်းပြီးတော့ Laravel Documentation ကို ပြုလုပ်ထားပါတယ်။ဒီမှာအရင်ဖတ်သင့်တာတွေကို ဖော်ပြထားပါတယ်: + + - [Installation](installation.md) and + [Configuration](configuration.md) + - [Routing](routing.md) + - [Requests & Input](requests.md) + - [Views & Responses](responses.md) + - [Controllers](controllers.md) + +အပေါ်က Documention Link တွေကိုဖတ်ပြီးပြီဆိုရင် သင့် အနေနဲ့ Laravel ရဲ့ request/response တွေကို ကောင်းကောင်း ကိုယ်တွယ်ဖြေရှင်းနိုင်သင့်ပါတယ်။ နောက်ပြီး သင်အနေနဲ့ [Database Configuration](database) / [Eloquent ORM](/docs/eloquent) ဖတ်ဖို့ဆုတောင်းကောင်းဆုတောင်းနေမယ်လို့ထင်ပါတယ် အဲ့ဒီလိုမှမဟုတ်ဘူးဆိုရင် [authentication and security](/docs/security.md) ကိုပေါ့ ဒါမှလူတွေကို သင့်ရဲ့ application ထဲကို sign in ဝင်ခိုင်းလို့ရမှာကိုး။ + + + +## Laravel သဘောတရား + +Laravel က ရိုးရှင်းသပ်ရပ်၊ မဟာဆန်ပြီး လှပနေတဲ့ syntax တွေနဲ ့ ရေးသားထားတဲ့ Web Application Framework တစ်ခုဖြစ်ပါတယ်၊ ကျွန်တော်တို့ Development က ပျော်စရာ ကောင်းရမယ် ဆိုတာကိုယုံကြည်ပါတယ်။ ဖန်တီးမှု တွေကိုလည်း စိတ်ချမ်းသာမူ အပြည့်အဝ ပေးမယ်လို့ယုံကြည်ပါတယ်။ Laravel က Web projects တွေရဲ့အဓိကအလုပ်တွေဖြစ်တဲ့ authernication, routing, sessions, နဲ့ caching တွေကို တက်နိုင်သမျှ လျှော့ချဖို့ ကြိုးစားနေပါတယ်။ + +Laravel ကနားလည်လွယ်တယ်၊ ဟုတ်ပါတယ် powerful လည်းဖြစ်တယ်၊ နောက် ကြီးမားရှုပ်ထွေးတဲ့ Projects တွေအတွက်လည်း အကောင်းဆုံး tools တွေကိုထောက်ပံ့နေပါတယ်။ ထိပ်တန်း ခွဲစိတ်မှူတစ်ခု control container,expressive migration system နဲ့ tightly integrated unit testing support tools တွေကိုသင့်ကိုပေးထားပါတယ် သင် Create လုပ်ချင်တဲ့ Application ကိုသင်စိတ်ကြိုက်လုပ်နိုင်ပါတယ်။ diff --git a/ioc.md b/ioc.md new file mode 100644 index 0000000..56a7099 --- /dev/null +++ b/ioc.md @@ -0,0 +1,186 @@ +# IoC Container + +- [Introduction](#introduction) +- [Basic Usage](#basic-usage) +- [Where To Register Bindings](#where-to-register) +- [Automatic Resolution](#automatic-resolution) +- [Practical Usage](#practical-usage) +- [Service Providers](#service-providers) +- [Container Events](#container-events) + + +## Introduction + +The Laravel inversion of control container is a powerful tool for managing class dependencies. Dependency injection is a method of removing hard-coded class dependencies. Instead, the dependencies are injected at run-time, allowing for greater flexibility as dependency implementations may be swapped easily. + +Understanding the Laravel IoC container is essential to building a powerful, large application, as well as for contributing to the Laravel core itself. + + +## Basic Usage + +#### Binding A Type Into The Container + +There are two ways the IoC container can resolve dependencies: via Closure callbacks or automatic resolution. First, we'll explore Closure callbacks. First, a "type" may be bound into the container: + + App::bind('foo', function($app) + { + return new FooBar; + }); + +#### Resolving A Type From The Container + + $value = App::make('foo'); + +When the `App::make` method is called, the Closure callback is executed and the result is returned. + +#### Binding A "Shared" Type Into The Container + +Sometimes, you may wish to bind something into the container that should only be resolved once, and the same instance should be returned on subsequent calls into the container: + + App::singleton('foo', function() + { + return new FooBar; + }); + +#### Binding An Existing Instance Into The Container + +You may also bind an existing object instance into the container using the `instance` method: + + $foo = new Foo; + + App::instance('foo', $foo); + + +## Where To Register Bindings + +IoC bindings, like event handlers or route filters, generally fall under the title of "bootstrap code". In other words, they prepare your application to actually handle requests, and usually need to be executed before a route or controller is actually called. Like most other bootstrap code, the `start` files are always an option for registering IoC bindings. Alternatively, you could create an `app/ioc.php` (filename does not matter) file and require that file from your `start` file. + +If your application has a very large number of IoC bindings, or you simply wish to organize your IoC bindings in separate files by category, you may register your bindings in a [service provider](#service-providers). + + +## Automatic Resolution + +#### Resolving A Class + +The IoC container is powerful enough to resolve classes without any configuration at all in many scenarios. For example: + + class FooBar { + + public function __construct(Baz $baz) + { + $this->baz = $baz; + } + + } + + $fooBar = App::make('FooBar'); + +Note that even though we did not register the FooBar class in the container, the container will still be able to resolve the class, even injecting the `Baz` dependency automatically! + +When a type is not bound in the container, it will use PHP's Reflection facilities to inspect the class and read the constructor's type-hints. Using this information, the container can automatically build an instance of the class. + +#### Binding An Interface To An Implementation + +However, in some cases, a class may depend on an interface implementation, not a "concrete type". When this is the case, the `App::bind` method must be used to inform the container which interface implementation to inject: + + App::bind('UserRepositoryInterface', 'DbUserRepository'); + +Now consider the following controller: + + class UserController extends BaseController { + + public function __construct(UserRepositoryInterface $users) + { + $this->users = $users; + } + + } + +Since we have bound the `UserRepositoryInterface` to a concrete type, the `DbUserRepository` will automatically be injected into this controller when it is created. + + +## Practical Usage + +Laravel provides several opportunities to use the IoC container to increase the flexibility and testability of your application. One primary example is when resolving controllers. All controllers are resolved through the IoC container, meaning you can type-hint dependencies in a controller constructor, and they will automatically be injected. + +#### Type-Hinting Controller Dependencies + + class OrderController extends BaseController { + + public function __construct(OrderRepository $orders) + { + $this->orders = $orders; + } + + public function getIndex() + { + $all = $this->orders->all(); + + return View::make('orders', compact('all')); + } + + } + +In this example, the `OrderRepository` class will automatically be injected into the controller. This means that when [unit testing](testing.md) a "mock" `OrderRepository` may be bound into the container and injected into the controller, allowing for painless stubbing of database layer interaction. + +#### Other Examples Of IoC Usage + +[Filters](routing#route-filters), [composers](/docs/responses#view-composers), and [event handlers](/docs/events#using-classes-as-listeners.md) may also be resolved out of the IoC container. When registering them, simply give the name of the class that should be used: + + Route::filter('foo', 'FooFilter'); + + View::composer('foo', 'FooComposer'); + + Event::listen('foo', 'FooHandler'); + + +## Service Providers + +Service providers are a great way to group related IoC registrations in a single location. Think of them as a way to bootstrap components in your application. Within a service provider, you might register a custom authentication driver, register your application's repository classes with the IoC container, or even setup a custom Artisan command. + +In fact, most of the core Laravel components include service providers. All of the registered service providers for your application are listed in the `providers` array of the `app/config/app.php` configuration file. + +#### Defining A Service Provider + +To create a service provider, simply extend the `Illuminate\Support\ServiceProvider` class and define a `register` method: + + use Illuminate\Support\ServiceProvider; + + class FooServiceProvider extends ServiceProvider { + + public function register() + { + $this->app->bind('foo', function() + { + return new Foo; + }); + } + + } + +Note that in the `register` method, the application IoC container is available to you via the `$this->app` property. Once you have created a provider and are ready to register it with your application, simply add it to the `providers` array in your `app` configuration file. + +#### Registering A Service Provider At Run-Time + +You may also register a service provider at run-time using the `App::register` method: + + App::register('FooServiceProvider'); + + +## Container Events + +#### Registering A Resolving Listener + +The container fires an event each time it resolves an object. You may listen to this event using the `resolving` method: + + App::resolvingAny(function($object) + { + // + }); + + App::resolving('foo', function($foo) + { + // + }); + +Note that the object that was resolved will be passed to the callback. diff --git a/license.md b/license.md index aa1f3d4..90ceb8b 100644 --- a/license.md +++ b/license.md @@ -1,4 +1,4 @@ -The MIT License (MIT) +MIT လိုင်စင်(MIT) Copyright © Taylor Otwell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/lifecycle.md b/lifecycle.md old mode 100644 new mode 100755 index a4adf21..d9aaa7e --- a/lifecycle.md +++ b/lifecycle.md @@ -1,52 +1,80 @@ # Request Lifecycle -- [Introduction](#introduction) -- [Lifecycle Overview](#lifecycle-overview) -- [Focus On Service Providers](#focus-on-service-providers) +- [Overview](#overview) +- [Request Lifecycle](#request-lifecycle) +- [Start Files](#start-files) +- [Application Events](#application-events) - -## Introduction + +## Overview -When using any tool in the "real world", you feel more confident if you understand how that tool works. Application development is no different. When you understand how your development tools function, you feel more comfortable and confident using them. +သင် tools တစ်ခုကို တကယ်လက်တွေ့သုံးပြီဆိုရင် အဲ့ဒီ tool က ဘယ်လိုအလုပ်လုပ်တယ်ဆိုတာကိုသိရင် သင်ပိုပြီး ယုံကြည်မှူရှိလာပါလိမ့်မယ်။ development tools တွေရဲ့ function တွေဘယ်လိုအလုပ်လုပ်လဲသင်သိလာတဲ့အခါမှာ သင်အဲဒါတွေကိုအသုံးပြုတဲ့အခါပိုပြီးတော့ အဆင်ပြေ ယုံကြည်လာပါလိမ့်မယ်။ ဒီ document ရဲ့ အဓိကရည်ရွယ်ချက်က Laravel Framework ဘယ်လိုအလုပ်လုပ်လဲဆိုတာကို ကောင်းမွန်တဲ့ hight-level overview တစ်ခုပေးဖို့ပါ။ Framework အကြောင်း overview ကောင်းကောင်းသိသွားတဲ့အချိန်မှာ "magical" လို့ထင်တာတွေနည်းသွားပြီးတော့ သင် application တည်ဆောက်ရာမှာပိုပြီးတော့ confident ရှိလာပါလိမ့်မယ်။ Request Lifecycle ရဲ့ hight level overview ရဲ့ဖြည့်စွတ်ချက်မှာတော့ "start" files နဲ့ application events ကိုပါ cover လုပ်ထားပါတယ်။ -The goal of this document is to give you a good, high-level overview of how the Laravel framework "works". By getting to know the overall framework better, everything feels less "magical" and you will be more confident building your applications. +တကယ်လို့သင့်အနေနဲ့ terms အားလုံးကိုနားမလည်ဘူးဆိုရင်စိတ်ထဲမထားပါနဲ့ ။ အခြေခံအားဖြင့် ဘယ်လိုလုပ်နေလဲဆိုတာကို ကြိုးစားကြည့်ပြီး documencation ရဲ့တစ်ခြား အပိုင်းတွေကို ဖတ်ပြီး သင့်ပိုပြီးသိလာပါလိမ့်မယ်။ -If you don't understand all of the terms right away, don't lose heart! Just try to get a basic grasp of what is going on, and your knowledge will grow as you explore other sections of the documentation. + +## Request Lifecycle - -## Lifecycle Overview +သင့် application ရဲ့ Request အားလုံးကို `public/index.php` ဆီကို redirect လုပ်ပါတယ်။ Apache ကိုအသုံးပြုတဲ့အခါမှာ `.htaccess` files က request အားလုံးကို `index.php` စီ redirect လုပ်ပေးပါတယ်။ အဲ့ဒီ့ကနေစပြီးတော့ Laravel က request တွေကိုလက်ခံတာ response တွေကို client ဆီပြန်ပေးတာတွေကို handles လုပ်ပေးသွားတာပါ၊ Laravel ရဲ့ bootstrap general idea က အသုံးဝင်ပါလိမ့်မယ် ၊ ဒါကြောင့်ကျွန်တော်တို့အခု အောက်မှာရှင်းပြပါ့မယ်။ -### First Things +Laravel ရဲ့ bootstrap process လေ့လာတဲ့နေရာမှာ **Service Providers** ကအဓိကဖြစ်ပါတယ်။ Services Providers တွေရဲ့ Lists တွေကို `app/config/app.php` ကိုဖွင့်ပြီး `providers` arrays မှာရှာတွေ့နိုင်ပါတယ်။ ဒီ providers တွေက Laravel ကို bootstrap လုပ်ဖို့ အဓိက ဖြစ်ပါတယ်။ သင့် `index.php` file ကို request တစ်ခုလုပ်လိုက်တာနဲ့ `bootstrap/start.php` က load လုပ်ပါမယ်။ အဲ့ဒီ့ file က Laravel `Application` object တွေကို create လုပ်ပါ့မယ်၊ နောက် [Ioc container](ioc.md) ကိုလည်း serve လုပ်ပါတယ်။ -The entry point for all requests to a Laravel application is the `public/index.php` file. All requests are directed to this file by your web server (Apache / Nginx) configuration. The `index.php` file doesn't contain much code. Rather, it is simply a starting point for loading the rest of the framework. +`Application` ရဲ့ object တွေကို create လုပ်ပြီးပြီဆိုရင်တော့ project ရဲ့ paths အချို့ကိုစတင်ပြီး တပ်ဆင်ပါ့မယ်၊ နောက် [environment detection](configuration#environment-configuration.md) တွေကိုဆက်လက်လုပ်ဆောင်ပါတယ်။ ဒါပြီးရင်တော့ Laravel bootstrap script တွေကို call လုပ်ပါ့မယ်။ Laravel source ရဲ့တွင်းပိုင်း File တွေထိ live ဖြစ်သွားပြီဆိုရင် သင့်ရဲ့ configuration ပေါ်မူတည်ပြီး setting တွေကို တပ်ဆင်ပါလိမ့်မယ်။ timezoneတို့၊ error reporting နဲ့ အခြား လိုအပ်တဲ့ setting တွေပေါ့။ ဒါပေမယ့် သင့် Application လိုအပ်တဲ့ Service Provider များအားလုံးကို register လုပ်ထားဖို့ကလည်း အခြား configuration တွေအားလုံးလိုပဲ အရေးကြီးပါတယ်။ -The `index.php` file loads the Composer generated autoloader definition, and then retrieves an instance of the Laravel application from `bootstrap/app.php` script. The first action taken by Laravel itself is to create an instance of the application / [service container](/docs/{{version}}/container). +Simple service providers only have one method: `register`. This `register` method is called when the service provider is registered with the application object via the application's own `register` method. Within this method, service providers register things with the [IoC container](ioc). Essentially, each service provider binds one or more [closures](http://us3.php.net/manual/en/functions.anonymous.php) into the container, which allows you to access those bound services within your application. So, for example, the `QueueServiceProvider` registers closures that resolve the various [Queue](/docs/queues.md) related classes. Of course, service providers may be used for any bootstrapping task, not just registering things with the IoC container. A service provider may register event listeners, view composers, Artisan commands, and more. -### HTTP / Console Kernels +Service Providers တွေအကုန်လုံး register လုပ်ပြီးရင် သင့်ရဲ့ `app/start` file loadလုပ်ပါလိမ့်မယ်။ နောက်ဆုံးအနေနဲ့သင့်ရဲ့ `app/routes.php` ကို load လုပ်ပါ့မယ်။ နောက်တစ်ခါသင့် application ရဲ့ `route.php` load လုပ်ပြီးရင် request objects တွေသင့် application ဆီကိုပို့ပါမယ်၊ ဒါက route တွေကိုစေလွှတ်ခြင်းဖြစ်ပါလိမ့်မယ်။ -Next, the incoming request is sent to either the HTTP kernel or the console kernel, depending on the type of request that is entering the application. These two kernels serve as the central location that all requests flow through. For now, let's just focus on the HTTP kernel, which is located in `app/Http/Kernel.php`. +ကဲဒါဆိုရင်အတိုချုပ်လိုက်ကြရအောင်: -The HTTP kernel extends the `Illuminate\Foundation\Http\Kernel` class, which defines an array of `bootstrappers` that will be run before the request is executed. These bootstrappers configure error handling, configure logging, [detect the application environment](/docs/{{version}}/installation#environment-configuration), and perform other tasks that need to be done before the request is actually handled. +1. Request တွေက `public/index.php` file ဆီကို ဝင်ရောက်လာတယ် +2. `bootstrap/start.php` file က Application ကို create လုပ်ပြီးတော့ environment ကို detect လုပ်တယ် +3. အတွင်းပိုင်း `framework/start.php` file က setting တွေကို configure လုပ်တယ်နောက်တော့ service providers တွေကို load လုပ်တယ် +4. Application ရဲ့ `app/start` file တွေ load လုပ်တယ် +5. Application ရဲ့ `app/route` file load လုပ်တယ် +6. Request objects တွေကို application ဆီကို ပို့တယ်၊ အဲဒီ့ကနေ object တွေ Response ပြန်လာတယ် +7. ပြန်လာတဲ့ Response တွေကို client ဆီကိုပြန်ပို့တယ် -The HTTP kernel also defines a list of HTTP [middleware](/docs/{{version}}/middleware) that all requests must pass through before being handled by the application. These middleware handle reading and writing the [HTTP session](/docs/{{version}}/session), determine if the application is in maintenance mode, [verifying the CSRF token](/docs/{{version}}/routing#csrf-protection), and more. +အခု Laravel က application ရဲ့ Request တွေကိုဘယ်လိုဖြေရှင်းသွားတယ်ဆိုတာသိပြီးသွားပြီ `start` file အကြောင်းကို နည်းနည်းအသေးစိတ်ဆက်လေ့လာလိုက်ကြအောင်။ -The method signature for the HTTP kernel's `handle` method is quite simple: receive a `Request` and return a `Response`. Think of the Kernel as being a big black box that represents your entire application. Feed it HTTP requests and it will return HTTP responses. + +## Start Files -#### Service Providers +သင့် Application ရဲ့ Start Files တွေက `app/start` ထဲမှာပါ။ Default အရဆိုရင် သင့် application ရဲ့ `global.php`,`local.php` နဲ့ `artisan.php` တို့ပါဝင်ပါတယ်။ artisan အကြောင်းအသေးစိတ်သိလိုတယ်ဆိုရင်တော့ [Artisan command line](command#registering-commands.md) ကိုဖတ်ဖို့ညွှန်းပရစေ။ -One of the most important Kernel bootstrapping actions is loading the [service providers](/docs/{{version}}/providers) for your application. All of the service providers for the application are configured in the `config/app.php` configuration file's `providers` array. First, the `register` method will be called on all providers, then, once all providers have been registered, the `boot` method will be called. +Default အရ`global.php` မှာ basic items တွေပါဝင်ပါတယ်၊ registration တွေရဲ့ [logger](errors.md) တို့... နောက် `app/filters.php` တို့လည်းပါဝင်ပါသေးတယ်။ ဒါပေမယ့်လည်း ဒီ `global.php` မှာ သင်ကြိုက်တဲ့ File တွေထက်ထည့်လို့ရပါတယ်။ တကယ်လို့ထက်ထည့်လိုက်ရင် အဲ့ဒီ့ File က သင့် application ရဲ့ request တိုင်းမှာ auto ပါဝင်နေမှာပါ။ `local.php` file ကတော့ `local` environment မှာမှ call လုပ်မှာပါ၊ +Environment configuration အကြောင်းအသေးစိတ်သိလိုတယ်ဆိုရင်တော့ [configuration](configuration.md) ကိုဖတ်ဖို့ ညွှန်းပရစေ။ -Service providers are responsible for bootstrapping all of the framework's various components, such as the database, queue, validation, and routing components. Since they bootstrap and configure every feature offered by the framework, service providers are the most important aspect of the entire Laravel bootstrap process. +ဟုတ်တာပေါ့ သင့်မှာ `local` environment တစ်ခုအပြင်အခြား environment တစ်ခုရှိတယ်ဆိုရင် အဲ့ဒီ့ environment အတွက် start file တစ်ခု create လုပ်ရမှာပေါ့။ နောက်အဲ့ဒီ့ start မှာပါတာတွေက သင်အဲ့ဒီ့ environment မှာအလုပ်လုပ်တဲ့အခါမှာ အလိုလိုပါလာမှပါ။ ဒါကြောင့် ..... ဥပမာ- သင့်မှာ `developemt` environment တစ်ခုရှပြီးတော့ `bootstrap/start.php` မှာ configre လုပ်ပြီးပြီဆိုရင် သင်အနေနဲ့ `app/start/development.php` file တစ်ခု create လုပ်ထားတယ်ဆိုရင် သင့် application က အဲ့ဒီ့ environment မှာ run ရင် `app/start/development.php` ကအလိုလိုပါဝင်နေမှာပါ။ -#### Dispatch Request +### What To Place In Start Files -Once the application has been bootstrapped and all service providers have been registered, the `Request` will be handed off to the router for dispatching. The router will dispatch the request to a route or controller, as well as run any route specific middleware. +Start files ကရိုးရိုးနေရာပါဘဲ...."bootstrapping" code တွေထည့်ရတဲ့နေရာပေါ့ ။ ဥပမာ၊ View composerတို့၊ logging preferences တွေကို configure လုပ်တာတို့ PHP Setting တွေပြောင်းတာ..နဲ့အခြားလိုအပ်တာတွေကို သင့် register လုပ်ချင်ရင်လဲလုပ်နိုင်ပါတယ်။ ဘာတွေကို register လုပ်ချင်လဲဆိုတာကတော့ သင့်အပေါ်မှာဘဲမူတည်ပါတယ်။ ဟုတ်တာပေါ့ "bootstrapping code" တွေအကုန်လုံးကိုသင့်ရဲ့ start file ထဲကိုထည့်လိုက်ရင် သင့်ရဲ့ start file တွေရှုပ်ပွကုန်မှာပေါ့။Application နည်းနည်းကြီးလာပြီဆိုရင် ဒါမှမဟုတ် သင့်ရဲ့ start files နည်းနည်းရှုပ်လာပြီလို့ခံစားရပြီဆိုရင်... bootstrapping code တွေကို [service providers](ioc#service-providers.md) တွေဆီရွှေ့လိုက်ပါ။ - -## Focus On Service Providers + +## Application Events -Service providers are truly the key to bootstrapping a Laravel application. The application instance is created, the service providers are registered, and the request is handed to the bootstrapped application. It's really that simple! +#### Registering Application Events -Having a firm grasp of how a Laravel application is built and bootstrapped via service providers is very valuable. Of course, your application's default service providers are stored in the `app/Providers` directory. +သင့်အနေနဲ့ pre request ၊ post request တွေစနစ်တစ်ကျသွားဖို့အတွက် before, after, finish, and shutdown application events တွေကိုသုံးရပါ့မယ် -By default, the `AppServiceProvider` is fairly empty. This provider is a great place to add your application's own bootstrapping and service container bindings. Of course, for large applications, you may wish to create several service providers, each with a more granular type of bootstrapping. + App::before(function($request) + { + // + }); + + App::after(function($request, $response) + { + // + }); + +အဲ့ဒီ့ event တွေပေါ်မူတည်ပြီးတော့ `before` နဲ့ `after` request တွေကို တစ်လှည့်ဆီသင့် application က run မှာပါ။ ဒီ events တွေက global filtering နဲ့ global modification တွေရဲ့ responses တွေအတွက်အလွန်အသုံးဝင်ပါလိမ့်မယ်။ သင့်အနေနဲ့ အဲ့ဒါတွေကို `start` files ဒါမှမဟုတ် [service provider](ioc#service-providers.md) မှာ register လုပ်ထားနိုင်ပါတယ်။ + +`matched` event ပေါ်က listener တစ်ခုကိုလည်း register လုပ်နိုင်ပါတယ်၊ request အဝင်တစ်ခုနဲ့ route တစ်ခုနဲ့ matched ဖြစ်သွားပြီဆိုရင် အဲဒါက fired လုပ်လိုက်တယ် ဒါပေမယ့် အဲ့ဒီ့ route က excute ဖြစ်မသွားပါဘူး။ + + Route::matched(function($route, $request) + { + // + }); + +သင် application က client ဆီကို sent လုပ်ပြီးသွားပြီဆိုရင် နောက်ဆုံး `finish` event ကို call လုပ်ပါတယ်။ သင် application ရဲ့နောက်ဆုံးမိနစ်လိုအပ်ချက်တွေကိုလုပ်ဖို့ဒါကနေရာကောင်းတစ်ခုပါ။ `finish` event handlers က အားလုံးပြီးသွားပြီဆိုရင် `shutdown` event ကိုချက်ချင်းခေါ်လိုက်ပါတယ်၊ ဒါကနောက်ဆုံး script အလုပ်မလုပ်ခင် လုပ်စရာရှိတာလုပ်ထားဖို့ နောက်ဆုံးအခွင့်အရေးပါ။ diff --git a/localization.md b/localization.md old mode 100644 new mode 100755 index e8b8ef7..eece9c0 --- a/localization.md +++ b/localization.md @@ -1,105 +1,109 @@ # Localization -- [Introduction](#introduction) -- [Retrieving Language Lines](#retrieving-language-lines) - - [Replacing Parameters In Language Lines](#replacing-parameters-in-language-lines) - - [Pluralization](#pluralization) +- [မိတ်ဆက်](#introduction) +- [Language Files](#language-files) +- [အခြေခံအသုံးပြုခြင်း](#basic-usage) +- [အများကိန်းပြုခြင်း](#pluralization) +- [Validation Localization](#validation) - [Overriding Package Language Files](#overriding-package-language-files) -## Introduction +## မိတ်ဆက် -Laravel's localization features provide a convenient way to retrieve strings in various languages, allowing you to easily support multiple languages within your application. Language strings are stored in files within the `resources/lang` directory. Within this directory there should be a subdirectory for each language supported by the application: +Laravel မှာပါတဲ့ `Lang` class ဟာ languages ဖိုင်တွေထဲမှာသတ်မှတ်ထားတဲ့ စကားစုတွေကို လွယ်ကူ အဆင်ပြေသော နည်းလမ်းတွေနဲ့ လက်ခံဆောင်ရွက်ပေးနိုင်ပါတယ်။ သင့် application အတွက် ဘာသာစကားမျိုးစုံကို လွယ်ကူစွာ အသုံးပြုနိုင်အောင်အထောက်အပံ့ပေးထားပါတယ်။ - /resources - /lang - /en - messages.php - /es - messages.php + +## Language Files -All language files simply return an array of keyed strings. For example: +`app/lang` လမ်းကြောင်းအောက်မှာ ဘာသာစကား စကားစုတွေကို သိမ်းဆည်းပါတယ်။ အဲ့ဒီလမ်းကြောင်းအောက်မှာတော့ သတ်မှတ်ချင်တဲ့ ဘာသာစကားတစ်ခုချင်းစီအတွက် ဖိုဒါတစ်ခုချင်းစီ ဆောက်ပြီးအသုံးပြုရမှာပါ။ - 'Welcome to our application' - ]; +#### Example Language File -### Configuring The Locale +ဘာသာစကားသတ်မှတ်ထားတဲ့ ဖိုင်ဆီကနေ keyed strings တွေပါတဲ့ array return ပြန်လာပါတယ်။ ဥပမာ - -The default language for your application is stored in the `config/app.php` configuration file. Of course, you may modify this value to suit the needs of your application. You may also change the active language at runtime using the `setLocale` method on the `App` facade: + 'Welcome to our application' + ); - // - }); +#### Changing The Default Language At Runtime -You may configure a "fallback language", which will be used when the active language does not contain a given language line. Like the default language, the fallback language is also configured in the `config/app.php` configuration file: +Application ရဲ့ ပုံမှန် ဘာသာစကားကိုတော့ `app/config/app.php` configuration ဖိုင်ထဲမှာ သတ်မှတ်ထားပါတယ်။ ဘာသာစကားများ တစ်ခုနဲ့တစ်ခု ပြောင်းလဲ အသုံးပြုချင်ရင်တော့ `App::setLocale` method ကိုအသုံးပြုနိုင်ပါတယ်။ - 'fallback_locale' => 'en', + App::setLocale('mm'); -#### Determining The Current Locale +#### Setting The Fallback Language -You may use the `getLocale` and `isLocale` methods on the `App` facade to determine the current locale or check if the locale is a given value: +"fallback language" အတွက်လည်း ပြင်ဆင်ထားနိုင်ပါတယ်။ "fallback language" ဆိုတာကတော့ လက်ရှိ သတ်မှတ်ထားတဲ့ ဘာသာစကား (language) ဖိုင်မှာ လိုအပ်နေတဲ့ စကားစု (language line) မပါလာတဲ့ အခြေအနေမျိုးမှာ အသုံးပြုဖို့အတွက်ဖြစ်ပါတယ်။ ပုံမှန်သတ်မှတ်နေကျအတိုင်းပဲ "fallback language" ကို `app/config/app.php` configuration ဖိုင်ထဲမှာသတ်မှတ်နိုင်ပါတယ်။ - $locale = App::getLocale(); + 'fallback_locale' => 'en', - if (App::isLocale('en')) { - // - } + +## အခြေခံအသုံးပြုနည်း - -## Retrieving Language Lines +#### ဘာသာစကားသတ်မှတ်ထားသော ဖိုင်မှ စကားစုများ ရယူခြင်း -You may retrieve lines from language files using the `trans` helper function. The `trans` method accepts the file and key of the language line as its first argument. For example, let's retrieve the `welcome` language line from the `resources/lang/messages.php` language file: + echo Lang::get('messages.welcome'); - echo trans('messages.welcome'); +`get`method ထဲကို passed လုပ်ထားတဲ့ string နှစ်ခုထဲမှ ပထမတစ်ခုကတော့ ဘာသာစကား (language) သတ်မှတ်ထားတဲ့ ဖိုင်ရဲ့ အမည်ဖြစ်ပြီး၊ ဒုတိယ တစ်ခုကတော့ array ထဲမှာသတ်မှတ်ထား စကားစုတွေရဲ့ key ဖြစ်ပါတယ်။ -Of course if you are using the [Blade templating engine](/docs/{{version}}/blade), you may use the `{{ }}` syntax to echo the language line or use the `@lang` directive: +> **သတိပြုရန်**: အကယ်၍ `get` နဲ့ ယူထားတဲ့ key အတွက် စကားစုဟာ ရှိမနေဘူးဆိုရင်တော့ key တစ်ခုပဲ return ပြန်လာပါလိမ့်မယ်။ - {{ trans('messages.welcome') }} +`trans` ဆိုတဲ့ helper function ကိုလည်း အသုံးပြုနိုင်ပါတယ်။ အဲ့ဒီ function ကတော့ `Lang::get` ဆိုတဲ့ method ကိုပဲ နာမည်ပြောင်းပြီးထပ်လုပ်ထားတာပါ။ - @lang('messages.welcome') + echo trans('messages.welcome'); -If the specified language line does not exist, the `trans` function will simply return the language line key. So, using the example above, the `trans` function would return `messages.welcome` if the language line does not exist. +#### စကားစုများ အစားထိုး ပြုလုပ်ခြင်း - -### Replacing Parameters In Language Lines +စကားစုတွေမှာ အစားထိုးဖို့ စကားလုံးတွေအတွက် place-holders လဲသတ်မှတ်နိုင်ပါသေးတယ်။ -If you wish, you may define place-holders in your language lines. All place-holders are prefixed with a `:`. For example, you may define a welcome message with a place-holder name: + 'welcome' => 'Welcome, :name', - 'welcome' => 'Welcome, :name', +ပြီးရင်တော့ `Lang::get` method ရဲ့ ဒုတိယ argument မှာ အစားထိုးချင်တဲ့ စကားလုံးကို passing ပေးလိုက်ပါ။ -To replace the place-holders when retrieving a language line, pass an array of replacements as the second argument to the `trans` function: + echo Lang::get('messages.welcome', array('name' => 'Dayle')); - echo trans('messages.welcome', ['name' => 'dayle']); +#### Determine If A Language File Contains A Line -If your place-holder contains all capital letters, or only has its first letter capitalized, the translated value will be capitalized accordingly: + if (Lang::has('messages.welcome')) + { + // + } - 'welcome' => 'Welcome, :NAME', // Welcome, DAYLE - 'goodbye' => 'Goodbye, :Name', // Goodbye, Dayle + +## အများကိန်းပြုလုပ်ခြင်း +အများကိန်းပြုလုပ်ခြင်းကိစ္စ ဟာ နည်းနည်းတော့ ရှုပ်ထွေးပါတယ်။ မတူညီတဲ့ languages တွေအတွက် မတူညီတဲ့ အများကိန်းပြုလုပ်နည်းတွေ ရှိပါတယ်။ Laravel မှာတော့ အများကိန်းပြုလုပ်ဖို့အတွက် "pipe" character ကို အနည်းကိန်းအတွက် ပြုလုပ်ထားတဲ့ စကားစုနဲ့ အများကိန်းအတွက်သတ်မှတ်မဲ့ စကားစုကြားမှာ ခံပြီးအသုံးပြုနိုင်ပါတယ်။ အများကိန်းပြုလုပ်တာကိုနားလည်ဖို့အတွက် အောက်ပါ ဥပမာကိုကြည့်ပါ။ - -### Pluralization + 'apples' => 'There is one apple|There are many apples', + +စကားစုတွေကို ယူသုံးဖို့အတွက်တော့ `Lang::choice` mehtod ကိုအသုံးပြုနိုင်ပါတယ်။ -Pluralization is a complex problem, as different languages have a variety of complex rules for pluralization. By using a "pipe" character, you may distinguish singular and plural forms of a string: + echo Lang::choice('messages.apples', 10); - 'apples' => 'There is one apple|There are many apples', +Local အတွက်သတ်မှတ်ထားတဲ့ စကားလုံးကိုလဲ သတ်မှတ်ပေးလိုက်နိုင်ပါတယ်။ ဥပမာ - Russian (ru) language ကိုအသုံးပြုချင်တယ်ဆိုရင် - -After defining a language line that has pluralization options, you may use the `trans_choice` function to retrieve the line for a given "count". In this example, since the count is greater than one, the plural form of the language line is returned: + echo Lang::choice('товар|товара|товаров', $count, array(), 'ru'); - echo trans_choice('messages.apples', 10); +Laravel translator ဟာ Symfony Translation component ကိုအသုံးပြုထားတဲ့အတွက်ကြောင့် သင့်အနေနဲ့ ပိုပြီး ရှင်းလင်းတိကျတဲ့ အများကိန်းပြုနည်း သတ်မှတ်ချက်ကို ပြုလုပ်နိုင်ပါတယ်။ -Since the Laravel translator is powered by the Symfony Translation component, you may create even more complex pluralization rules which specify language lines for multiple number ranges: + 'apples' => '{0} There are none|[1,19] There are some|[20,Inf] There are many', - 'apples' => '{0} There are none|[1,19] There are some|[20,Inf] There are many', + + +## Validation + +Localization အတွက် အသုံးပြုနိုင်တဲ့ validation errors နဲ့ messages တွေကိုတော့ အသုံးပြုနည်း လမ်းညွှန်ရဲ့Validation မှာ ကြည့်နိုင်ပါတယ်။ ## Overriding Package Language Files -Some packages may ship with their own language files. Instead of changing the package's core files to tweak these lines, you may override them by placing files in the `resources/lang/vendor/{package}/{locale}` directory. - -So, for example, if you need to override the English language lines in `messages.php` for a package named `skyrim/hearthfire`, you should place a language file at: `resources/lang/vendor/hearthfire/en/messages.php`. Within this file, you should only define the language lines you wish to override. Any language lines you don't override will still be loaded from the package's original language files. +Laravel နဲ့အတူ တွဲစပ်အသုံးပြုနိုင်တဲ့ packages တွေမှာ သူတို့ရဲ့ ကိုယ်ပိုင် ဘာသာစကားဖိုင်တွေတစ်ပါတည်းပါလာပါတယ်။ အဲ့ဒီဖိုင်တွေကို change ဖို့ packages တွေရဲ့ မူရင်းဖိုင်တွေကို သွားပြင်နေမဲ့အစား `app/lang/packages/{locale}/{package}` လမ်းကြောင်းအောက်ကနေတစ်ဆင့် override ပြုလုပ်နိုင်ပါတယ်။ ဥပမာ `skyrim/hearthfire` လို့ အမည်တွင်တဲ့ package အတွက် `messages.php` ဖိုင်ထဲမှာရှိတဲ့ English Language ကို override လုပ်ချင်တယ်ဆိုရင် `app/lang/packages/en/hearthfire/messages.php` ဖိုင်ကနေတစ်ဆင့် ပြုလုပ်နိုင်ပါတယ်။ Override လုပ်ဖို့လိုအပ်တဲ့ စကားစုတွေကိုပဲ အဲ့ဒီဖိုင်ထဲမှာသတ်မှတ်ထားဖို့လိုအပ်ပါတယ်။ ကျန်တဲ့စကားစုအားလုံးကိုတော့ package ရဲ့ language ဖိုင်ထဲက နေပဲ အလုပ်လုပ်သွားမှာဖြစ်ပါတယ်။ diff --git a/mail.md b/mail.md old mode 100644 new mode 100755 index 3e0b21b..a0cd992 --- a/mail.md +++ b/mail.md @@ -1,422 +1,136 @@ # Mail -- [Introduction](#introduction) - - [Driver Prerequisites](#driver-prerequisites) -- [Generating Mailables](#generating-mailables) -- [Writing Mailables](#writing-mailables) - - [Configuring The Sender](#configuring-the-sender) - - [Configuring The View](#configuring-the-view) - - [View Data](#view-data) - - [Attachments](#attachments) - - [Inline Attachments](#inline-attachments) -- [Sending Mail](#sending-mail) - - [Queueing Mail](#queueing-mail) +- [Configuration](#configuration) +- [Basic Usage](#basic-usage) +- [Embedding Inline Attachments](#embedding-inline-attachments) +- [Queueing Mail](#queueing-mail) - [Mail & Local Development](#mail-and-local-development) -- [Events](#events) - -## Introduction + +## Configuration -Laravel provides a clean, simple API over the popular [SwiftMailer](http://swiftmailer.org) library with drivers for SMTP, Mailgun, SparkPost, Amazon SES, PHP's `mail` function, and `sendmail`, allowing you to quickly get started sending mail through a local or cloud based service of your choice. +Laravel provides a clean, simple API over the popular [SwiftMailer](http://swiftmailer.org) library. The mail configuration file is `app/config/mail.php`, and contains options allowing you to change your SMTP host, port, and credentials, as well as set a global `from` address for all messages delivered by the library. You may use any SMTP server you wish. If you wish to use the PHP `mail` function to send mail, you may change the `driver` to `mail` in the configuration file. A `sendmail` driver is also available. - -### Driver Prerequisites +### API Drivers -The API based drivers such as Mailgun and SparkPost are often simpler and faster than SMTP servers. If possible, you should use one of these drivers. All of the API drivers require the Guzzle HTTP library, which may be installed via the Composer package manager: +Laravel also includes drivers for the Mailgun and Mandrill HTTP APIs. These APIs are often simpler and quicker than the SMTP servers. Both of these drivers require that the Guzzle 4 HTTP library be installed into your application. You can add Guzzle 4 to your project by adding the following line to your `composer.json` file: - composer require guzzlehttp/guzzle + "guzzlehttp/guzzle": "~4.0" #### Mailgun Driver -To use the Mailgun driver, first install Guzzle, then set the `driver` option in your `config/mail.php` configuration file to `mailgun`. Next, verify that your `config/services.php` configuration file contains the following options: +To use the Mailgun driver, set the `driver` option to `mailgun` in your `app/config/mail.php` configuration file. Next, create an `app/config/services.php` configuration file if one does not already exist for your project. Verify that it contains the following options: - 'mailgun' => [ - 'domain' => 'your-mailgun-domain', - 'secret' => 'your-mailgun-key', - ], + 'mailgun' => array( + 'domain' => 'your-mailgun-domain', + 'secret' => 'your-mailgun-key', + ), -#### SparkPost Driver +#### Mandrill Driver -To use the SparkPost driver, first install Guzzle, then set the `driver` option in your `config/mail.php` configuration file to `sparkpost`. Next, verify that your `config/services.php` configuration file contains the following options: +To use the Mailgun driver, set the `driver` option to `mandrill` in your `app/config/mail.php` configuration file. Next, create an `app/config/services.php` configuration file if one does not already exist for your project. Verify that it contains the following options: - 'sparkpost' => [ - 'secret' => 'your-sparkpost-key', - ], + 'mandrill' => array( + 'secret' => 'your-mandrill-key', + ), -#### SES Driver +### Log Driver -To use the Amazon SES driver you must first install the Amazon AWS SDK for PHP. You may install this library by adding the following line to your `composer.json` file's `require` section and running the `composer update` command: +If the `driver` option of your `app/config/mail.php` configuration file is set to `log`, all e-mails will be written to your log files, and will not actually be sent to any of the recipients. This is primarily useful for quick, local debugging and content verification. - "aws/aws-sdk-php": "~3.0" + +## Basic Usage -Next, set the `driver` option in your `config/mail.php` configuration file to `ses` and verify that your `config/services.php` configuration file contains the following options: +The `Mail::send` method may be used to send an e-mail message: - 'ses' => [ - 'key' => 'your-ses-key', - 'secret' => 'your-ses-secret', - 'region' => 'ses-region', // e.g. us-east-1 - ], + Mail::send('emails.welcome', $data, function($message) + { + $message->to('foo@example.com', 'John Smith')->subject('Welcome!'); + }); - -## Generating Mailables +The first argument passed to the `send` method is the name of the view that should be used as the e-mail body. The second is the `$data` that should be passed to the view, and the third is a Closure allowing you to specify various options on the e-mail message. -In Laravel, each type of email sent by your application is represented as a "mailable" class. These classes are stored in the `app/Mail` directory. Don't worry if you don't see this directory in your application, since it will be generated for you when you create your first mailable class using the `make:mail` command: +> **Note:** A `$message` variable is always passed to e-mail views, and allows the inline embedding of attachments. So, it is best to avoid passing a `message` variable in your view payload. - php artisan make:mail OrderShipped +You may also specify a plain text view to use in addition to an HTML view: - -## Writing Mailables + Mail::send(array('html.view', 'text.view'), $data, $callback); -All of a mailable class' configuration is done in the `build` method. Within this method, you may call various methods such as `from`, `subject`, `view`, and `attach` to configure the email's presentation and delivery. +Or, you may specify only one type of view using the `html` or `text` keys: - -### Configuring The Sender + Mail::send(array('text' => 'view'), $data, $callback); -#### Using The `from` Method +You may specify other options on the e-mail message such as any carbon copies or attachments as well: -First, let's explore configuring the sender of the email. Or, in other words, who the email is going to be "from". There are two ways to configure the sender. First, you may use the `from` method within your mailable class' `build` method: + Mail::send('emails.welcome', $data, function($message) + { + $message->from('us@example.com', 'Laravel'); - /** - * Build the message. - * - * @return $this - */ - public function build() - { - return $this->from('example@example.com') - ->view('emails.orders.shipped'); - } + $message->to('foo@example.com')->cc('bar@example.com'); -#### Using A Global `from` Address + $message->attach($pathToFile); + }); -However, if your application uses the same "from" address for all of its emails, it can become cumbersome to call the `from` method in each mailable class you generate. Instead, you may specify a global "from" address in your `config/mail.php` configuration file. This address will be used if no other "from" address is specified within the mailable class: +When attaching files to a message, you may also specify a MIME type and / or a display name: - 'from' => ['address' => 'example@example.com', 'name' => 'App Name'], + $message->attach($pathToFile, array('as' => $display, 'mime' => $mime)); - -### Configuring The View +> **Note:** The message instance passed to a `Mail::send` Closure extends the SwiftMailer message class, allowing you to call any method on that class to build your e-mail messages. -Within a mailable class' `build` method, you may use the `view` method to specify which template should be used when rendering the email's contents. Since each email typically uses a [Blade template](/docs/{{version}}/blade) to render its contents, you have the full power and convenience of the Blade templating engine when building your email's HTML: + +## Embedding Inline Attachments - /** - * Build the message. - * - * @return $this - */ - public function build() - { - return $this->view('emails.orders.shipped'); - } +Embedding inline images into your e-mails is typically cumbersome; however, Laravel provides a convenient way to attach images to your e-mails and retrieving the appropriate CID. -> {tip} You may wish to create a `resources/views/emails` directory to house all of your email templates; however, you are free to place them wherever you wish within your `resources/views` directory. +#### Embedding An Image In An E-Mail View -#### Plain Text Emails + + Here is an image: -If you would like to define a plain-text version of your email, you may use the `text` method. Like the `view` method, the `text` method accepts a template name which will be used to render the contents of the email. You are free to define both a HTML and plain-text version of your message: + + - /** - * Build the message. - * - * @return $this - */ - public function build() - { - return $this->view('emails.orders.shipped') - ->text('emails.orders.shipped_plain'); - } +#### Embedding Raw Data In An E-Mail View - -### View Data + + Here is an image from raw data: -#### Via Public Properties + + -Typically, you will want to pass some data to your view that you can utilize when rendering the email's HTML. There are two ways you may make data available to your view. First, any public property defined on your mailable class will automatically be made available to the view. So, for example, you may pass data into your mailable class' constructor and set that data to public properties defined on the class: - - order = $order; - } - - /** - * Build the message. - * - * @return $this - */ - public function build() - { - return $this->view('emails.orders.shipped'); - } - } - -Once the data has been set to a public property, it will automatically be available in your view, so you may access it like you would access any other data in your Blade templates: - -
    - Price: {{ $order->price }} -
    - -#### Via The `with` Method: - -If you would like to customize the format of your email's data before it is sent to the template, you may manually pass your data to the view via the `with` method. Typically, you will still pass data via the mailable class' constructor; however, you should set this data to `protected` or `private` properties so the data is not automatically made available to the template. Then, when calling the `with` method, pass an array of data that you wish to make available to the template: - - order = $order; - } - - /** - * Build the message. - * - * @return $this - */ - public function build() - { - return $this->view('emails.orders.shipped') - ->with([ - 'orderName' => $this->order->name, - 'orderPrice' => $this->order->price, - ]); - } - } - -Once the data has been passed to the `with` method, it will automatically be available in your view, so you may access it like you would access any other data in your Blade templates: - -
    - Price: {{ $orderPrice }} -
    - - -### Attachments - -To add attachments to an email, use the `attach` method within the mailable class' `build` method. The `attach` method accepts the full path to the file as its first argument: - - /** - * Build the message. - * - * @return $this - */ - public function build() - { - return $this->view('emails.orders.shipped') - ->attach('/path/to/file'); - } - -When attaching files to a message, you may also specify the display name and / or MIME type by passing an `array` as the second argument to the `attach` method: - - /** - * Build the message. - * - * @return $this - */ - public function build() - { - return $this->view('emails.orders.shipped') - ->attach('/path/to/file', [ - 'as' => 'name.pdf', - 'mime' => 'application/pdf', - ]); - } - -#### Raw Data Attachments - -The `attachData` method may be used to attach a raw string of bytes as an attachment. For example, you might use this method if you have generated a PDF in memory and want to attach it to the email without writing it to disk. The `attachData` method accepts the raw data bytes as its first argument, the name of the file as its second argument, and an array of options as its third argument: - - /** - * Build the message. - * - * @return $this - */ - public function build() - { - return $this->view('emails.orders.shipped') - ->attachData($this->pdf, 'name.pdf', [ - 'mime' => 'application/pdf', - ]); - } - - -### Inline Attachments - -Embedding inline images into your emails is typically cumbersome; however, Laravel provides a convenient way to attach images to your emails and retrieving the appropriate CID. To embed an inline image, use the `embed` method on the `$message` variable within your email template. Laravel automatically makes the `$message` variable available to all of your email templates, so you don't need to worry about passing it in manually: - - - Here is an image: - - - - -#### Embedding Raw Data Attachments - -If you already have a raw data string you wish to embed into an email template, you may use the `embedData` method on the `$message` variable: - - - Here is an image from raw data: - - - - - -## Sending Mail - -To send a message, use the `to` method on the `Mail` [facade](/docs/{{version}}/facades). The `to` method accepts an email address, a user instance, or a collection of users. If you pass an object or collection of objects, the mailer will automatically use their `email` and `name` properties when setting the email recipients, so make sure these attributes are available on your objects. Once you have specified your recipients, you may pass an instance of your mailable class to the `send` method: - - user())->send(new OrderShipped($order)); - } - } - -Of course, you are not limited to just specifying the "to" recipients when sending a message. You are free to set "to", "cc", and "bcc" recipients all within a single, chained method call: - - Mail::to($request->user()) - ->cc($moreUsers) - ->bcc($evenMoreUsers) - ->send(new OrderShipped($order)); +Note that the `$message` variable is always passed to e-mail views by the `Mail` class. -### Queueing Mail +## Queueing Mail #### Queueing A Mail Message -Since sending email messages can drastically lengthen the response time of your application, many developers choose to queue email messages for background sending. Laravel makes this easy using its built-in [unified queue API](/docs/{{version}}/queues). To queue a mail message, use the `queue` method on the `Mail` facade after specifying the message's recipients: - - Mail::to($request->user()) - ->cc($moreUsers) - ->bcc($evenMoreUsers) - ->queue(new OrderShipped($order)); - -This method will automatically take care of pushing a job onto the queue so the message is sent in the background. Of course, you will need to [configure your queues](/docs/{{version}}/queues) before using this feature. - -#### Delayed Message Queueing - -If you wish to delay the delivery of a queued email message, you may use the `later` method. As its first argument, the `later` method accepts a `DateTime` instance indicating when the message should be sent: - - $when = Carbon\Carbon::now()->addMinutes(10); +Since sending e-mail messages can drastically lengthen the response time of your application, many developers choose to queue e-mail messages for background sending. Laravel makes this easy using its built-in [unified queue API](queues.md). To queue a mail message, simply use the `queue` method on the `Mail` class: - Mail::to($request->user()) - ->cc($moreUsers) - ->bcc($evenMoreUsers) - ->later($when, new OrderShipped($order)); + Mail::queue('emails.welcome', $data, function($message) + { + $message->to('foo@example.com', 'John Smith')->subject('Welcome!'); + }); -#### Pushing To Specific Queues +You may also specify the number of seconds you wish to delay the sending of the mail message using the `later` method: -Since all mailable classes generated using the `make:mail` command make use of the `Illuminate\Bus\Queueable` trait, you may call the `onQueue` and `onConnection` methods on any mailable class instance, allowing you to specify the connection and queue name for the message: + Mail::later(5, 'emails.welcome', $data, function($message) + { + $message->to('foo@example.com', 'John Smith')->subject('Welcome!'); + }); - $message = (new OrderShipped($order)) - ->onConnection('sqs') - ->onQueue('emails'); +If you wish to specify a specific queue or "tube" on which to push the message, you may do so using the `queueOn` and `laterOn` methods: - Mail::to($request->user()) - ->cc($moreUsers) - ->bcc($evenMoreUsers) - ->queue($message); + Mail::queueOn('queue-name', 'emails.welcome', $data, function($message) + { + $message->to('foo@example.com', 'John Smith')->subject('Welcome!'); + }); ## Mail & Local Development -When developing an application that sends email, you probably don't want to actually send emails to live email addresses. Laravel provides several ways to "disable" the actual sending of emails during local development. - -#### Log Driver - -Instead of sending your emails, the `log` mail driver will write all email messages to your log files for inspection. For more information on configuring your application per environment, check out the [configuration documentation](/docs/{{version}}/installation#environment-configuration). - -#### Universal To - -Another solution provided by Laravel is to set a universal recipient of all emails sent by the framework. This way, all the emails generated by your application will be sent to a specific address, instead of the address actually specified when sending the message. This can be done via the `to` option in your `config/mail.php` configuration file: - - 'to' => [ - 'address' => 'example@example.com', - 'name' => 'Example' - ], - -#### Mailtrap - -Finally, you may use a service like [Mailtrap](https://mailtrap.io) and the `smtp` driver to send your email messages to a "dummy" mailbox where you may view them in a true email client. This approach has the benefit of allowing you to actually inspect the final emails in Mailtrap's message viewer. - - -## Events - -Laravel fires an event just before sending mail messages. Remember, this event is fired when the mail is *sent*, not when it is queued. You may register an event listener for this event in your `EventServiceProvider`: +When developing an application that sends e-mail, it's usually desirable to disable the sending of messages from your local or development environment. To do so, you may either call the `Mail::pretend` method, or set the `pretend` option in the `app/config/mail.php` configuration file to `true`. When the mailer is in `pretend` mode, messages will be written to your application's log files instead of being sent to the recipient. - /** - * The event listener mappings for the application. - * - * @var array - */ - protected $listen = [ - 'Illuminate\Mail\Events\MessageSending' => [ - 'App\Listeners\LogSentMessage', - ], - ]; +#### Enabling Pretend Mail Mode + Mail::pretend(); \ No newline at end of file diff --git a/middleware.md b/middleware.md deleted file mode 100644 index f50f33b..0000000 --- a/middleware.md +++ /dev/null @@ -1,250 +0,0 @@ -# Middleware - -- [Introduction](#introduction) -- [Defining Middleware](#defining-middleware) -- [Registering Middleware](#registering-middleware) - - [Global Middleware](#global-middleware) - - [Assigning Middleware To Routes](#assigning-middleware-to-routes) - - [Middleware Groups](#middleware-groups) -- [Middleware Parameters](#middleware-parameters) -- [Terminable Middleware](#terminable-middleware) - - -## Introduction - -Middleware provide a convenient mechanism for filtering HTTP requests entering your application. For example, Laravel includes a middleware that verifies the user of your application is authenticated. If the user is not authenticated, the middleware will redirect the user to the login screen. However, if the user is authenticated, the middleware will allow the request to proceed further into the application. - -Of course, additional middleware can be written to perform a variety of tasks besides authentication. A CORS middleware might be responsible for adding the proper headers to all responses leaving your application. A logging middleware might log all incoming requests to your application. - -There are several middleware included in the Laravel framework, including middleware for authentication and CSRF protection. All of these middleware are located in the `app/Http/Middleware` directory. - - -## Defining Middleware - -To create a new middleware, use the `make:middleware` Artisan command: - - php artisan make:middleware CheckAge - -This command will place a new `CheckAge` class within your `app/Http/Middleware` directory. In this middleware, we will only allow access to the route if the supplied `age` is greater than 200. Otherwise, we will redirect the users back to the `home` URI. - - age <= 200) { - return redirect('home'); - } - - return $next($request); - } - - } - -As you can see, if the given `age` is less than or equal to `200`, the middleware will return an HTTP redirect to the client; otherwise, the request will be passed further into the application. To pass the request deeper into the application (allowing the middleware to "pass"), simply call the `$next` callback with the `$request`. - -It's best to envision middleware as a series of "layers" HTTP requests must pass through before they hit your application. Each layer can examine the request and even reject it entirely. - -### Before & After Middleware - -Whether a middleware runs before or after a request depends on the middleware itself. For example, the following middleware would perform some task **before** the request is handled by the application: - - -## Registering Middleware - - -### Global Middleware - -If you want a middleware to run during every HTTP request to your application, simply list the middleware class in the `$middleware` property of your `app/Http/Kernel.php` class. - - -### Assigning Middleware To Routes - -If you would like to assign middleware to specific routes, you should first assign the middleware a key in your `app/Http/Kernel.php` file. By default, the `$routeMiddleware` property of this class contains entries for the middleware included with Laravel. To add your own, simply append it to this list and assign it a key of your choosing. For example: - - // Within App\Http\Kernel Class... - - protected $routeMiddleware = [ - 'auth' => \Illuminate\Auth\Middleware\Authenticate::class, - 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, - 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, - 'can' => \Illuminate\Auth\Middleware\Authorize::class, - 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, - 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, - ]; - -Once the middleware has been defined in the HTTP kernel, you may use the `middleware` method to assign middleware to a route: - - Route::get('admin/profile', function () { - // - })->middleware('auth'); - -Use an array to assign multiple middleware to the route: - - Route::get('/', function () { - // - })->middleware('first', 'second'); - -When assigning middleware, you may also pass the fully qualified class name: - - use App\Http\Middleware\CheckAge; - - Route::get('admin/profile', function () { - // - })->middleware(CheckAge::class); - - -### Middleware Groups - -Sometimes you may want to group several middleware under a single key to make them easier to assign to routes. You may do this using the `$middlewareGroups` property of your HTTP kernel. - -Out of the box, Laravel comes with `web` and `api` middleware groups that contains common middleware you may want to apply to your web UI and API routes: - - /** - * The application's route middleware groups. - * - * @var array - */ - protected $middlewareGroups = [ - 'web' => [ - \App\Http\Middleware\EncryptCookies::class, - \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, - \Illuminate\Session\Middleware\StartSession::class, - \Illuminate\View\Middleware\ShareErrorsFromSession::class, - \App\Http\Middleware\VerifyCsrfToken::class, - \Illuminate\Routing\Middleware\SubstituteBindings::class, - ], - - 'api' => [ - 'throttle:60,1', - 'auth:api', - ], - ]; - -Middleware groups may be assigned to routes and controller actions using the same syntax as individual middleware. Again, middleware groups simply make it more convenient to assign many middleware to a route at once: - - Route::get('/', function () { - // - })->middleware('web'); - - Route::group(['middleware' => ['web']], function () { - // - }); - -> {tip} Out of the box, the `web` middleware group is automatically applied to your `routes/web.php` file by the `RouteServiceProvider`. - - -## Middleware Parameters - -Middleware can also receive additional parameters. For example, if your application needs to verify that the authenticated user has a given "role" before performing a given action, you could create a `CheckRole` middleware that receives a role name as an additional argument. - -Additional middleware parameters will be passed to the middleware after the `$next` argument: - - user()->hasRole($role)) { - // Redirect... - } - - return $next($request); - } - - } - -Middleware parameters may be specified when defining the route by separating the middleware name and parameters with a `:`. Multiple parameters should be delimited by commas: - - Route::put('post/{id}', function ($id) { - // - })->middleware('role:editor'); - - -## Terminable Middleware - -Sometimes a middleware may need to do some work after the HTTP response has been sent to the browser. For example, the "session" middleware included with Laravel writes the session data to storage after the response has been sent to the browser. If you define a `terminate` method on your middleware, it will automatically be called after the response is sent to the browser. - - -## Introduction - -Migrations are like version control for your database, allowing your team to easily modify and share the application's database schema. Migrations are typically paired with Laravel's schema builder to easily build your application's database schema. If you have ever had to tell a teammate to manually add a column to their local database schema, you've faced the problem that database migrations solve. - -The Laravel `Schema` [facade](/docs/{{version}}/facades) provides database agnostic support for creating and manipulating tables across all of Laravel's supported database systems. - - -## Generating Migrations - -To create a migration, use the `make:migration` [Artisan command](/docs/{{version}}/artisan): +- [အစပျိုး](#introduction) +- [Migrations ဖန်တီးခြင်း](#creating-migrations) +- [Migrations ပြုလုပ်ခြင်း](#running-migrations) +- [Migrations နောက်ပြန်ခြင်း](#rolling-back-migrations) +- [Database Seeding](#database-seeding) - php artisan make:migration create_users_table - -The new migration will be placed in your `database/migrations` directory. Each migration file name contains a timestamp which allows Laravel to determine the order of the migrations. - -The `--table` and `--create` options may also be used to indicate the name of the table and whether the migration will be creating a new table. These options simply pre-fill the generated migration stub file with the specified table: - - php artisan make:migration create_users_table --create=users + +## အစပျိုး - php artisan make:migration add_votes_to_users_table --table=users +Migration မှာ Database အတွက် Version Control ပြုလုပ်နိုင်ရန် ဖန်တီးထားသည်။ ၄င်းကို အသုံးပြုခြင်းဖြင့် database schema များကို အလွယ်တကူ ပြင်ဆင်နိုင်ပြီး team တစ်ခုလုံး တူညီသည့် database schema ကို အသုံးပြုနိုင်ရန် ပံပိုးထားသည်။ Migrations မှာ ပှံမှန်အားဖြင့် [Schema Builder](schema.md) ဖြင့် တွဲဖက် အသုံးပြုကြသည်။ -If you would like to specify a custom output path for the generated migration, you may use the `--path` option when executing the `make:migration` command. The given path should be relative to your application's base path. + +## Migrations ဖန်တီးခြင်း - -## Migration Structure +migration တစ်ခု ဖန်တီးနိုင်ရန် Artisan CLI တွင် `migrate:make` ဟူသည် command ကို အသုံးပြုနိုင်သည်။ -A migration class contains two methods: `up` and `down`. The `up` method is used to add new tables, columns, or indexes to your database, while the `down` method should simply reverse the operations performed by the `up` method. + php artisan migrate:make create_users_table -Within both of these methods you may use the Laravel schema builder to expressively create and modify tables. To learn about all of the methods available on the `Schema` builder, [check out its documentation](#creating-tables). For example, this migration example creates a `flights` table: +Migration file များသည် `app/database/migrations` ဆိုသည့် folder တွင်တည်ရှိမည် ဖြစ်ပြီး Migrations များကို အစဉ်အတိုင်း စီရီထားမည့် timestamp ဖြင့် သတ်မှတ်ထားမည် ဖြစ်သည်။ - increments('id'); - $table->string('name'); - $table->string('airline'); - $table->timestamps(); - }); - } + +`--table` နှင့် `--create` options များကို အသုံးပြု၍ table အမည်ကို သတ်မှတ်ခြင်း ၊ table အသစ်ကို ဖန်တီးခြင်း များ ပြုလုပ်နိုင်ပါမည်။ - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::drop('flights'); - } - } + php artisan migrate:make add_votes_to_user_table --table=users + php artisan migrate:make create_users_table --create=users -## Running Migrations - -To run all of your outstanding migrations, execute the `migrate` Artisan command: - - php artisan migrate - -> {note} If you are using the [Homestead virtual machine](/docs/{{version}}/homestead), you should run this command from within your virtual machine. - -#### Forcing Migrations To Run In Production - -Some migration operations are destructive, which means they may cause you to lose data. In order to protect you from running these commands against your production database, you will be prompted for confirmation before the commands are executed. To force the commands to run without a prompt, use the `--force` flag: - - php artisan migrate --force - - -### Rolling Back Migrations - -To rollback the latest migration operation, you may use the `rollback` command. This command rolls back the last "batch" of migrations, which may include multiple migration files: - - php artisan migrate:rollback - -You may rollback a limited number of migrations by providing the `step` option to the `rollback` command. For example, the following command will rollback the last five migrations: - - php artisan migrate:rollback --step=5 - -The `migrate:reset` command will roll back all of your application's migrations: - - php artisan migrate:reset - -#### Rollback & Migrate In Single Command - -The `migrate:refresh` command will roll back all of your migrations and then execute the `migrate` command. This command effectively re-creates your entire database: - - php artisan migrate:refresh - - // Refresh the database and run all database seeds... - php artisan migrate:refresh --seed - -You may rollback & re-migrate a limited number of migrations by providing the `step` option to the `refresh` command. For example, the following command will rollback & re-migrate the last five migrations: - - php artisan migrate:refresh --step=5 - - -## Tables - - -### Creating Tables - -To create a new database table, use the `create` method on the `Schema` facade. The `create` method accepts two arguments. The first is the name of the table, while the second is a `Closure` which receives a `Blueprint` object that may be used to define the new table: - - Schema::create('users', function (Blueprint $table) { - $table->increments('id'); - }); - -Of course, when creating the table, you may use any of the schema builder's [column methods](#creating-columns) to define the table's columns. - -#### Checking For Table / Column Existence - -You may easily check for the existence of a table or column using the `hasTable` and `hasColumn` methods: - - if (Schema::hasTable('users')) { - // - } - - if (Schema::hasColumn('users', 'email')) { - // - } - -#### Connection & Storage Engine - -If you want to perform a schema operation on a database connection that is not your default connection, use the `connection` method: +## Migrations ပြုလုပ်ခြင်း - Schema::connection('foo')->create('users', function ($table) { - $table->increments('id'); - }); +#### Migration ကို အပြည့်အဝ ပြုလုပ်ခြင်း -You may use the `engine` property on the schema builder to define the table's storage engine: + php artisan migrate - Schema::create('users', function ($table) { - $table->engine = 'InnoDB'; +#### Path လမ်းကြောင်းတစ်ခုတွင်သာ Migration ပြုလုပ်ခြင်း - $table->increments('id'); - }); + php artisan migrate --path=app/foo/migrations - -### Renaming / Dropping Tables +#### Package တစ်ခုအတွက် Migration ပြုလုပ်ခြင်း -To rename an existing database table, use the `rename` method: + php artisan migrate --package=vendor/package - Schema::rename($from, $to); +> **သတိပြုရန်:** migrations run နေစဉ် "class not found" ဟု error တွေ ့ရှိပါက `composer dump-autoload` ဆိုသည့် command ကို run ကြည့်ပါ။ -To drop an existing table, you may use the `drop` or `dropIfExists` methods: +### Production တွင် Migration ပြုလုပ်ခြင်း - Schema::drop('users'); +အချို ့သော migration operations များမှာ အန္တာရယ်များလှပေသည်။ တနည်းအားဖြင့် သင့်၏ အချက်အလက်များကို စက္ကန် ့ပိုင်းအတွင် ဆုံးရှုံးသွားစေနိုင်သည်။ အဆိုပါ အန္တာရယ်မှ ကာကွယ်နိုင်ရန် production အခြေအနေတွင် migration ပြုလုပ်ရန် confirmation တောင်းခံပါသည်။ ထိုတောင်းခံမှုကို ကျော်လွှားလိုပါက `--force` flag ကို အသုံးပြုနိုင်သည်။ - Schema::dropIfExists('users'); + php artisan migrate --force -#### Renaming Tables With Foreign Keys - -Before renaming a table, you should verify that any foreign key constraints on the table have an explicit name in your migration files instead of letting Laravel assign a convention based name. Otherwise, the foreign key constraint name will refer to the old table name. - - -## Columns - - -### Creating Columns - -The `table` method on the `Schema` facade may be used to update existing tables. Like the `create` method, the `table` method accepts two arguments: the name of the table and a `Closure` that receives a `Blueprint` instance you may use to add columns to the table: - - Schema::table('users', function ($table) { - $table->string('email'); - }); - -#### Available Column Types - -Of course, the schema builder contains a variety of column types that you may specify when building your tables: - -Command | Description -------------- | ------------- -`$table->bigIncrements('id');` | Incrementing ID (primary key) using a "UNSIGNED BIG INTEGER" equivalent. -`$table->bigInteger('votes');` | BIGINT equivalent for the database. -`$table->binary('data');` | BLOB equivalent for the database. -`$table->boolean('confirmed');` | BOOLEAN equivalent for the database. -`$table->char('name', 4);` | CHAR equivalent with a length. -`$table->date('created_at');` | DATE equivalent for the database. -`$table->dateTime('created_at');` | DATETIME equivalent for the database. -`$table->dateTimeTz('created_at');` | DATETIME (with timezone) equivalent for the database. -`$table->decimal('amount', 5, 2);` | DECIMAL equivalent with a precision and scale. -`$table->double('column', 15, 8);` | DOUBLE equivalent with precision, 15 digits in total and 8 after the decimal point. -`$table->enum('choices', ['foo', 'bar']);` | ENUM equivalent for the database. -`$table->float('amount');` | FLOAT equivalent for the database. -`$table->increments('id');` | Incrementing ID (primary key) using a "UNSIGNED INTEGER" equivalent. -`$table->integer('votes');` | INTEGER equivalent for the database. -`$table->ipAddress('visitor');` | IP address equivalent for the database. -`$table->json('options');` | JSON equivalent for the database. -`$table->jsonb('options');` | JSONB equivalent for the database. -`$table->longText('description');` | LONGTEXT equivalent for the database. -`$table->macAddress('device');` | MAC address equivalent for the database. -`$table->mediumInteger('numbers');` | MEDIUMINT equivalent for the database. -`$table->mediumText('description');` | MEDIUMTEXT equivalent for the database. -`$table->morphs('taggable');` | Adds INTEGER `taggable_id` and STRING `taggable_type`. -`$table->nullableTimestamps();` | Same as `timestamps()`, except allows NULLs. -`$table->rememberToken();` | Adds `remember_token` as VARCHAR(100) NULL. -`$table->smallInteger('votes');` | SMALLINT equivalent for the database. -`$table->softDeletes();` | Adds `deleted_at` column for soft deletes. -`$table->string('email');` | VARCHAR equivalent column. -`$table->string('name', 100);` | VARCHAR equivalent with a length. -`$table->text('description');` | TEXT equivalent for the database. -`$table->time('sunrise');` | TIME equivalent for the database. -`$table->timeTz('sunrise');` | TIME (with timezone) equivalent for the database. -`$table->tinyInteger('numbers');` | TINYINT equivalent for the database. -`$table->timestamp('added_on');` | TIMESTAMP equivalent for the database. -`$table->timestampTz('added_on');` | TIMESTAMP (with timezone) equivalent for the database. -`$table->timestamps();` | Adds `created_at` and `updated_at` columns. -`$table->uuid('id');` | UUID equivalent for the database. - - -### Column Modifiers - -In addition to the column types listed above, there are several column "modifiers" you may use while adding a column to a database table. For example, to make the column "nullable", you may use the `nullable` method: - - Schema::table('users', function ($table) { - $table->string('email')->nullable(); - }); - -Below is a list of all the available column modifiers. This list does not include the [index modifiers](#creating-indexes): - -Modifier | Description -------------- | ------------- -`->first()` | Place the column "first" in the table (MySQL Only) -`->after('column')` | Place the column "after" another column (MySQL Only) -`->nullable()` | Allow NULL values to be inserted into the column -`->default($value)` | Specify a "default" value for the column -`->unsigned()` | Set `integer` columns to `UNSIGNED` -`->comment('my comment')` | Add a comment to a column - - - -### Modifying Columns - -#### Prerequisites - -Before modifying a column, be sure to add the `doctrine/dbal` dependency to your `composer.json` file. The Doctrine DBAL library is used to determine the current state of the column and create the SQL queries needed to make the specified adjustments to the column: - - composer require doctrine/dbal - -#### Updating Column Attributes - -The `change` method allows you to modify an existing column to a new type or modify the column's attributes. For example, you may wish to increase the size of a string column. To see the `change` method in action, let's increase the size of the `name` column from 25 to 50: - - Schema::table('users', function ($table) { - $table->string('name', 50)->change(); - }); - -We could also modify a column to be nullable: - - Schema::table('users', function ($table) { - $table->string('name', 50)->nullable()->change(); - }); - -> {note} Modifying any column in a table that also has a column of type `enum`, `json` or `jsonb` is not currently supported. - - -#### Renaming Columns - -To rename a column, you may use the `renameColumn` method on the Schema builder. Before renaming a column, be sure to add the `doctrine/dbal` dependency to your `composer.json` file: - - Schema::table('users', function ($table) { - $table->renameColumn('from', 'to'); - }); - -> {note} Renaming any column in a table that also has a column of type `enum`, `json` or `jsonb` is not currently supported. - - -### Dropping Columns - -To drop a column, use the `dropColumn` method on the Schema builder. Before dropping columns from a SQLite database, you will need to add the `doctrine/dbal` dependency to your `composer.json` file and run the `composer update` command in your terminal to install the library: - - Schema::table('users', function ($table) { - $table->dropColumn('votes'); - }); - -You may drop multiple columns from a table by passing an array of column names to the `dropColumn` method: - - Schema::table('users', function ($table) { - $table->dropColumn(['votes', 'avatar', 'location']); - }); - -> {note} Dropping or modifying multiple columns within a single migration while using a SQLite database is not supported. - - -## Indexes - - -### Creating Indexes - -The schema builder supports several types of indexes. First, let's look at an example that specifies a column's values should be unique. To create the index, we can simply chain the `unique` method onto the column definition: - - $table->string('email')->unique(); - -Alternatively, you may create the index after defining the column. For example: - - $table->unique('email'); + +## Rolling Back Migrations -You may even pass an array of columns to an index method to create a compound index: +#### Migrations နောက်ပြန်ခြင်း - $table->index(['account_id', 'created_at']); + php artisan migrate:rollback -Laravel will automatically generate a reasonable index name, but you may pass a second argument to the method to specify the name yourself: +#### Migrations ပထမဆုံး အခြေအနေသို ့ နောက်ပြန်ခြင်း - $table->index('email', 'my_index_name'); + php artisan migrate:reset -#### Available Index Types +#### အစမှ အဆုံး နောက်ပြန်ပြီးနောက် တဖန် Migration ပြုလုပ်ခြင်း -Command | Description -------------- | ------------- -`$table->primary('id');` | Add a primary key. -`$table->primary(['first', 'last']);` | Add composite keys. -`$table->unique('email');` | Add a unique index. -`$table->unique('state', 'my_index_name');` | Add a custom index name. -`$table->index('state');` | Add a basic index. + php artisan migrate:refresh - -### Dropping Indexes + php artisan migrate:refresh --seed -To drop an index, you must specify the index's name. By default, Laravel automatically assigns a reasonable name to the indexes. Simply concatenate the table name, the name of the indexed column, and the index type. Here are some examples: + +## Database Seeding -Command | Description -------------- | ------------- -`$table->dropPrimary('users_id_primary');` | Drop a primary key from the "users" table. -`$table->dropUnique('users_email_unique');` | Drop a unique index from the "users" table. -`$table->dropIndex('geo_state_index');` | Drop a basic index from the "geo" table. +Laravel အနေဖြင့် database ကို အလွယ်တကူ seed ပြုလုပ်နိုင်ရင် seed classes များပါရှိပါသည်။ Seed class များမှာ `app/database/seeds` တွင်တည်ရှိမည် ဖြစ်သည်။ Seed class များကို အလိုရှိသလို အမည်ပေးနိုင်သော်လည်း အဓိပ္ပါယ်ရှိသော နာမည်မျိုး ဥပမာ `UserTableSeeder` စသဖြင့်သာ ပေးသင့်သည်။ ပုံမှန်အားဖြင့် `DatabaseSeeder` class မှာ ဖန်တီးပေးထားသည်။ ထို class မှ သင့်အနေဖြင့် `call` method ကို အသုံးပြုကာ +အစီအစဉ်အလိုက် အခြားသော seed classes များကို run နိုင်သည်။ -If you pass an array of columns into a method that drops indexes, the conventional index name will be generated based on the table name, columns and key type: +#### Example Database Seed Class - Schema::table('geo', function ($table) { - $table->dropIndex(['state']); // Drops index 'geo_state_index' - }); + class DatabaseSeeder extends Seeder { - -### Foreign Key Constraints + public function run() + { + $this->call('UserTableSeeder'); -Laravel also provides support for creating foreign key constraints, which are used to force referential integrity at the database level. For example, let's define a `user_id` column on the `posts` table that references the `id` column on a `users` table: + $this->command->info('User table seeded!'); + } - Schema::table('posts', function ($table) { - $table->integer('user_id')->unsigned(); + } - $table->foreign('user_id')->references('id')->on('users'); - }); + class UserTableSeeder extends Seeder { -You may also specify the desired action for the "on delete" and "on update" properties of the constraint: + public function run() + { + DB::table('users')->delete(); - $table->foreign('user_id') - ->references('id')->on('users') - ->onDelete('cascade'); + User::create(array('email' => 'foo@bar.com')); + } -To drop a foreign key, you may use the `dropForeign` method. Foreign key constraints use the same naming convention as indexes. So, we will concatenate the table name and the columns in the constraint then suffix the name with "_foreign": + } - $table->dropForeign('posts_user_id_foreign'); +Database ကို seed ပြုလုပ်ရန် Artisan CLI မှ `db:seed` command ကို အသုံးပြုနိုင်သည်။ -Or, you may pass an array value which will automatically use the conventional constraint name when dropping: + php artisan db:seed - $table->dropForeign(['user_id']); +ပုံမှန်အားဖြင့် `db:seed` command မှာ `DatabaseSeeder` class ကို run မည်ဖြစ်ပြီး ထိုမှတဆင့် အခြား seed class များကို ခေါ်ယူမည် ဖြစ်သည်။ သို ့ပင်သော်ညား `--class` option ကို အသုံးပြုကာ သီးသန် ့ seeder class တစ်ခုချင်းစီလည်း run နိုင်ပါသေးသည်။ -You may enable or disable foreign key constraints within your migrations by using the following methods: + php artisan db:seed --class=UserTableSeeder - Schema::enableForeignKeyConstraints(); +ထိုအပြင် `migrate:refresh` ကိုအသုံးပြုကာ, rollback ပြုလုပ်ပြီး migrations ကို အစမှ တဖန်ပြန်၍ run ခြင်းကိုလည်း ပြုလုပ်နိုင်မည် ဖြစ်သည်။ - Schema::disableForeignKeyConstraints(); + php artisan migrate:refresh --seed diff --git a/mocking.md b/mocking.md deleted file mode 100644 index d67f802..0000000 --- a/mocking.md +++ /dev/null @@ -1,178 +0,0 @@ -# Mocking - -- [Introduction](#introduction) -- [Events](#mocking-events) -- [Jobs](#mocking-jobs) -- [Facades](#mocking-facades) - - -## Introduction - -When testing Laravel applications, you may wish to "mock" certain aspects of your application so they are not actually executed during a given test. For example, when testing a controller that fires an event, you may wish to mock the event listeners so they are not actually executed during the test. This allows you to only test the controller's HTTP response without worrying about the execution of the event listeners, since the event listeners can be tested in their own test case. - -Laravel provides helpers for mocking events, jobs, and facades out of the box. These helpers primarily provide a convenience layer over Mockery so you do not have to manually make complicated Mockery method calls. Of course, are free to use [Mockery](http://docs.mockery.io/en/latest/) or PHPUnit to create your own mocks or spies. - - -## Events - -If you are making heavy use of Laravel's event system, you may wish to silence or mock certain events while testing. For example, if you are testing user registration, you probably do not want all of a `UserRegistered` event's handlers firing, since the listeners may send "welcome" e-mails, etc. - -Laravel provides a convenient `expectsEvents` method which verifies the expected events are fired, but prevents any listeners for those events from executing: - - expectsEvents(UserRegistered::class); - - // Test user registration... - } - } - -You may use the `doesntExpectEvents` method to verify that the given events are not fired: - - expectsEvents(OrderShipped::class); - $this->doesntExpectEvents(OrderFailedToShip::class); - - // Test order shipping... - } - } - -If you would like to prevent all event listeners from running, you may use the `withoutEvents` method. When this method is called, all listeners for all events will be mocked: - - withoutEvents(); - - // Test user registration code... - } - } - - -## Jobs - -Sometimes, you may wish to test that given jobs are dispatched when making requests to your application. This will allow you to test your routes and controllers in isolation without worrying about your job's logic. Of course, you should then test the job in a separate test case. - -Laravel provides the convenient `expectsJobs` method which will verify that the expected jobs are dispatched. However, the job itself will not be executed: - - expectsJobs(ShipOrder::class); - - // Test order shipping... - } - } - -> {note} This method only detects jobs that are dispatched via the `DispatchesJobs` trait's dispatch methods or the `dispatch` helper function. It does not detect queued jobs that are sent directly to `Queue::push`. - -Like the event mocking helpers, you may also test that a job is not dispatched using the `doesntExpectJobs` method: - - doesntExpectJobs(ShipOrder::class); - - // Test order cancellation... - } - } - -Alternatively, you may ignore all dispatched jobs using the `withoutJobs` method. When this method is called within a test method, all jobs that are dispatched during that test will be discarded: - - withoutJobs(); - - // Test order cancellation... - } - } - - -## Facades - -Unlike traditional static method calls, [facades](/docs/{{version}}/facades) may be mocked. This provides a great advantage over traditional static methods and grants you the same testability you would have if you were using dependency injection. When testing, you may often want to mock a call to a Laravel facade in one of your controllers. For example, consider the following controller action: - - once() - ->with('key') - ->andReturn('value'); - - $this->visit('/users')->see('value'); - } - } - -> {note} You should not mock the `Request` facade. Instead, pass the input you desire into the HTTP helper methods such as `call` and `post` when running your test. diff --git a/notifications.md b/notifications.md deleted file mode 100644 index 9a4ca42..0000000 --- a/notifications.md +++ /dev/null @@ -1,637 +0,0 @@ -# Notifications - -- [Introduction](#introduction) -- [Creating Notifications](#creating-notifications) -- [Sending Notifications](#sending-notifications) - - [Using The Notifiable Trait](#using-the-notifiable-trait) - - [Using The Notification Facade](#using-the-notification-facade) - - [Specifying Delivery Channels](#specifying-delivery-channels) - - [Queueing Notifications](#queueing-notifications) -- [Mail Notifications](#mail-notifications) - - [Formatting Mail Messages](#formatting-mail-messages) - - [Customizing The Recipient](#customizing-the-recipient) - - [Customizing The Subject](#customizing-the-subject) - - [Error Messages](#error-messages) -- [Database Notifications](#database-notifications) - - [Prerequisites](#database-prerequisites) - - [Formatting Database Notifications](#formatting-database-notifications) - - [Accessing The Notifications](#accessing-the-notifications) - - [Marking Notifications As Read](#marking-notifications-as-read) -- [Broadcast Notifications](#broadcast-notifications) - - [Prerequisites](#broadcast-prerequisites) - - [Formatting Broadcast Notifications](#formatting-broadcast-notifications) - - [Listening For Notifications](#listening-for-notifications) -- [SMS Notifications](#sms-notifications) - - [Prerequisites](#sms-prerequisites) - - [Formatting SMS Notifications](#formatting-sms-notifications) - - [Customizing The "From" Number](#customizing-the-from-number) - - [Routing SMS Notifications](#routing-sms-notifications) -- [Slack Notifications](#slack-notifications) - - [Prerequisites](#slack-prerequisites) - - [Formatting Slack Notifications](#formatting-slack-notifications) - - [Routing Slack Notifications](#routing-slack-notifications) -- [Notification Events](#notification-events) -- [Custom Channels](#custom-channels) - -## Introduction - -In addition to support for [sending email](/docs/{{version}}/mail), Laravel provides support for sending notifications across a variety of delivery channels, including mail, SMS (via [Nexmo](https://www.nexmo.com/)), and [Slack](https://slack.com). Notifications may also be stored in a database so they may be displayed in your web interface. - -Typically, notifications should be short, informational messages that notify users of something that occurred in your application. For example, if you are writing a billing application, you might send an "Invoice Paid" notification to your users via the email and SMS channels. - - -## Creating Notifications - -In Laravel, each notification is represented by a single class (typically stored in the `app/Notifications` directory). Don't worry if you don't see this directory in your application, it will be created for you when you run the `make:notification` Artisan command: - - php artisan make:notification InvoicePaid - -This command will place a fresh notification class in your `app/Notifications` directory. Each notification class contains a `via` method and a variable number of message building methods (such as `toMail` or `toDatabase`) that convert the notification to a message optimized for that particular channel. - - -## Sending Notifications - - -### Using The Notifiable Trait - -Notifications may be sent in two ways: using the `notify` method of the `Notifiable` trait or using the `Notification` [facade](/docs/{{version}}/facades). First, let's examine the `Notifiable` trait. This trait is used by the default `App\User` model and contains one method that may be used to send notifications: `notify`. The `notify` method expects to receive a notification instance: - - use App\Notifications\InvoicePaid; - - $user->notify(new InvoicePaid($invoice)); - -> {tip} Remember, you may use the `Illuminate\Notifications\Notifiable` trait on any of your models. You are not limited to only including it on your `User` model. - - -### Using The Notification Facade - -Alternatively, you may send notifications via the `Notification` [facade](/docs/{{version}}facades). This is useful primarily when you need to send a notification to multiple notifiable entities such as a collection of users. To send notifications using the facade, pass all of the notifiable entities and the notification instance to the `send` method: - - Notification::send($users, new InvoicePaid($invoice)); - - -### Specifying Delivery Channels - -Every notification class has a `via` method that determines on which channels the notification will be delivered. Out of the box, notifications may be sent on the `mail`, `database`, `broadcast`, `nexmo`, and `slack` channels. - -> {tip} If you would like to use other delivery channels such as Telegram or Pusher, check out the community driven [Laravel Notification Channels website](http://laravel-notification-channels.com). - -The `via` method receives a `$notifiable` instance, which will be an instance of the class to which the notification is being sent. You may use `$notifiable` to determine which channels the notification should be delivered on: - - /** - * Get the notification's delivery channels. - * - * @param mixed $notifiable - * @return array - */ - public function via($notifiable) - { - return $notifiable->prefers_sms ? ['nexmo'] : ['mail', 'database']; - } - - -### Queueing Notifications - -> {note} Before queueing notifications you should configure your queue and [start a worker](/docs/{{version}}/queues). - -Sending notifications can take time, especially if the channel needs an external API call to deliver the notification. To speed up your application's response time, let your notification be queued by adding the `ShouldQueue` interface and `Queueable` trait to your class. The interface and trait are already imported for all notifications generated using `make:notification`, so you may immediately add them to your notification class: - - notify(new InvoicePaid($invoice)); - -If you would like to delay the deliver of the notification, you may chain the `delay` method onto your notification instantiation: - - $when = Carbon::now()->addMinutes(10); - - $user->notify((new InvoicePaid($invoice))->delay($when)); - - -## Mail Notifications - - -### Formatting Mail Messages - -If a notification supports being sent as an email, you should define a `toMail` method on the notification class. This method will receive a `$notifiable` entity and should return a `Illuminate\Notifications\Messages\MailMessage` instance. Mail messages may contains lines of text as well as a "call to action". Let's take a look at an example `toMail` method: - - /** - * Get the mail representation of the notification. - * - * @param mixed $notifiable - * @return \Illuminate\Notifications\Messages\MailMessage - */ - public function toMail($notifiable) - { - $url = url('/invoice/'.$this->invoice->id); - - return (new MailMessage) - ->line('One of your invoices has been paid!') - ->action('View Invoice', $url) - ->line('Thank you for using our application!'); - } - -> {tip} Note we are using `$this->invoice->id` in our `message` method. You may pass any data your notification needs to generate its message into the notification's constructor. - -In this example, we register a line of text, a call to action, and then another line of text. These methods provided by the `MailMessage` object make it simple and fast to format small transactional emails. The mail channel will then translate the message components into a nice, responsive HTML email template. Here is an example of an email generated by the `mail` channel: - - - - -### Customizing The Recipient - -When sending notifications via the `mail` channel, the notification system will automatically look for an `email` property on your notifiable entity. You may customize which email address is used to deliver the notification by defining a `routeNotificationForMail` method on the entity: - - email_address; - } - } - - -### Customizing The Subject - -By default, the email's subject is the class name of the notification formatted to "title case". So, if your notification class is named `InvoicePaid`, the email's subject will be `Invoice Paid`. If you would like to specify an explicit subject for the message, you may call the `subject` method when building your message: - - /** - * Get the mail representation of the notification. - * - * @param mixed $notifiable - * @return \Illuminate\Notifications\Messages\MailMessage - */ - public function toMail($notifiable) - { - return (new MailMessage) - ->subject('Notification Subject') - ->line('...') - } - - -### Error Messages - -Some notifications inform users of errors, such as a failed invoice payment. You may indicate that a mail message is regarding an error by calling the `error` method when building your message. When using the `error` method on a mail message, the call to action button will be red instead of blue: - - /** - * Get the mail representation of the notification. - * - * @param mixed $notifiable - * @return \Illuminate\Notifications\Message - */ - public function toMail($notifiable) - { - return (new MailMessage) - ->error() - ->subject('Notification Subject') - ->line('...') - } - - -## Database Notifications - - -### Prerequisites - -The `database` notification channel stores the notification information in a database table. This table will contain information such as the notification type as well as custom JSON data that describes the notification. - -You can query the table to display the notifications in your application's user interface. But, before you can do that, you will need to create a database table to hold your notifications. You may use the `notifications:table` command to generate a migration with the proper table schema: - - php artisan notifications:table - - php artisan migrate - - -### Formatting Database Notifications - -If a notification supports being stored in a database table, you should define a `toDatabase` or `toArray` method on the notification class. This method will receive a `$notifiable` entity and should return a plain PHP array. The returned array will be encoded as JSON and stored in the `data` column of your `notifications` table. Let's take a look at an example `toArray` method: - - /** - * Get the array representation of the notification. - * - * @param mixed $notifiable - * @return array - */ - public function toArray($notifiable) - { - return [ - 'invoice_id' => $this->invoice->id, - 'amount' => $this->invoice->amount, - ]; - } - -#### `toDatabase` Vs. `toArray` - -The `toArray` method is also used by the `broadcast` channel to determine which data to broadcast to your JavaScript client. If you would like to have two different array representations for the `database` and `broadcast` channels, you should define a `toDatabase` method instead of a `toArray` method. - - -### Accessing The Notifications - -Once notifications are stored in the database, you need a convenient way to access them from your notifiable entities. The `Illuminate\Notifications\Notifiable` trait, which is included on Laravel's default `App\User` model, includes a `notifications` Eloquent relationship that returns the notifications for the entity. To fetch notifications, you may access this method like any other Eloquent relationship. By default, notifications will be sorted by the `created_at` timestamp: - - $user = App\User::find(1); - - foreach ($user->notifications as $notification) { - echo $notification->type; - } - -If you want to retrieve only the "unread" notifications, you may use the `unreadNotifications` relationship. Again, these notifications will be sorted by the `created_at` timestamp: - - $user = App\User::find(1); - - foreach ($user->unreadNotifications as $notification) { - echo $notification->type; - } - -> {tip} To access your notifications from your JavaScript client, you should define a notification controller for your application which returns the notifications for a notifiable entity, such as the current user. You may then make an HTTP request to that controller's URI from your JavaScript client. - - -### Marking Notifications As Read - -Typically, you will want to mark a notification as "read" when a user views it. The `Illuminate\Notifications\Notifiable` trait provides a `markAsRead` method, which updates the `read_at` column on the notification's database record: - - $user = App\User::find(1); - - foreach ($user->notifications as $notification) { - $notification->markAsRead(); - } - -However, instead of looping through each notification, you may use the `markAsRead` method directly on a collection of notifications: - - $user->notifications->markAsRead(); - -You may also use a mass-update query to mark all of the notifications as read without retrieving them from the database: - - $user = App\User::find(1); - - $user->notifications()->update(['read_at' => Carbon::now()]); - -Of course, you may `delete` the notifications to remove them from the table entirely: - - $user->notifications()->delete(); - - -## Broadcast Notifications - - -### Prerequisites - -Before broadcasting notifications, you should configure and be familiar with Laravel's [event broadcasting](/docs/{{version}}/broadcasting) services. Event broadcasting provides a way to react to server-side fired Laravel events from your JavaScript client. - - -### Formatting Broadcast Notifications - -The `broadcast` channel broadcasts notifications using Laravel's [event broadcasting](/docs/{{version}}/broadcasting) services, allowing your JavaScript client to catch notifications in realtime. If a notification supports broadcasting, you should define a `toBroadcast` or `toArray` method on the notification class. This method will receive a `$notifiable` entity and should return a plain PHP array. The returned array will be encoded as JSON and broadcast to your JavaScript client. Let's take a look at an example `toArray` method: - - /** - * Get the array representation of the notification. - * - * @param mixed $notifiable - * @return array - */ - public function toArray($notifiable) - { - return [ - 'invoice_id' => $this->invoice->id, - 'amount' => $this->invoice->amount, - ]; - } - -> {tip} In addition to the data you specify, broadcast notifications will also contain a `type` field containing the class name of the notification. - -#### `toBroadcast` Vs. `toArray` - -The `toArray` method is also used by the `database` channel to determine which data to store in your database table. If you would like to have two different array representations for the `database` and `broadcast` channels, you should define a `toBroadcast` method instead of a `toArray` method. - - -### Listening For Notifications - -Notifications will broadcast on a private channel formatted using a `{notifiable}.{id}` convention. So, if you are sending a notification to a `App\User` instance with an ID of `1`, the notification will be broadcast on the `App.User.1` private channel. When using [Laravel Echo](/docs/{{version}}/broadcasting), you may easily listen for notifications on a channel using the `notification` helper method: - - Echo.private('App.User.' + userId) - .notification((notification) => { - console.log(notification.type); - }); - - -## SMS Notifications - - -### Prerequisites - -Sending SMS notifications in Laravel is powered by [Nexmo](https://www.nexmo.com/). Before you can send notifications via Nexmo, you need to install the `nexmo/client` Composer package and add a few configuration options to your `config/services.php` configuration file. You may copy the example configuration below to get started: - - 'nexmo' => [ - 'key' => env('NEXMO_KEY'), - 'secret' => env('NEXMO_SECRET'), - 'sms_from' => '15556666666', - ], - -The `sms_from` option is the phone number that your SMS messages will be sent from. You should generate a phone number for your application in the Nexmo control panel. - - -### Formatting SMS Notifications - -If a notification supports being sent as a SMS, you should define a `toNexmo` method on the notification class. This method will receive a `$notifiable` entity and should return a `Illuminate\Notifications\Messages\NexmoMessage` instance: - - /** - * Get the Nexmo / SMS representation of the notification. - * - * @param mixed $notifiable - * @return NexmoMessage - */ - public function toNexmo($notifiable) - { - return (new NexmoMessage) - ->content('Your SMS message content'); - } - - -### Customizing The "From" Number - -If you would like to send some notifications from a phone number that is different from the phone number specified in your `config/services.php` file, you may use the `from` method on a `NexmoMessage` instance: - - /** - * Get the Nexmo / SMS representation of the notification. - * - * @param mixed $notifiable - * @return NexmoMessage - */ - public function toNexmo($notifiable) - { - return (new NexmoMessage) - ->content('Your SMS message content') - ->from('15554443333'); - } - - -### Routing SMS Notifications - -When sending notifications via the `nexmo` channel, the notification system will automatically look for a `phone_number` attribute on the notifiable entity. If you would like to customize the phone number the notification is delivered to, define a `routeNotificationForNexmo` method on the entity: - - phone; - } - } - - -## Slack Notifications - - -### Prerequisites - -Before you can send notifications via Slack, you must install the Guzzle HTTP library via Composer: - - composer require guzzlehttp/guzzle - -You will also need to configure an "Incoming Webhook" integration for your Slack team. This integration will provide you with a URL you may use when [routing Slack notifications](#routing-slack-notifications). - - -### Formatting Slack Notifications - -If a notification supports being sent as a Slack message, you should define a `toSlack` method on the notification class. This method will receive a `$notifiable` entity and should return a `Illuminate\Notifications\Messages\SlackMessage` instance. Slack messages may contain text content as well as an "attachment" that formats additional text or an array of fields. Let's take a look at a basic `toSlack` example: - - /** - * Get the Slack representation of the notification. - * - * @param mixed $notifiable - * @return SlackMessage - */ - public function toSlack($notifiable) - { - return (new SlackMessage) - ->content('One of your invoices has been paid!'); - } - -In this example we are just sending a single line of text to Slack, which will create a message that looks like the following: - - - -#### Slack Attachments - -You may also add "attachments" to Slack messages. Attachments provide richer formatting options than simple text messages. In this example, we will send an error notification about an exception that occurred in an application, including a link to view more details about the exception: - - /** - * Get the Slack representation of the notification. - * - * @param mixed $notifiable - * @return SlackMessage - */ - public function toSlack($notifiable) - { - $url = url('/exceptions/'.$this->exception->id); - - return (new SlackMessage) - ->error() - ->content('Whoops! Something went wrong.') - ->attachment(function ($attachment) use ($url) { - $attachment->title('Exception: File Not Found', $url) - ->content('File [background.jpg] was not found.'); - }); - } - -The example above will generate a Slack message that looks like the following: - - - -Attachments also allow you to specify an array of data that should be presented to the user. The given data will be presented in a table-style format for easy reading: - - /** - * Get the Slack representation of the notification. - * - * @param mixed $notifiable - * @return SlackMessage - */ - public function toSlack($notifiable) - { - $url = url('/invoices/'.$this->invoice->id); - - return (new SlackMessage) - ->success() - ->content('One of your invoices has been paid!') - ->attachment(function ($attachment) use ($url) { - $attachment->title('Invoice 1322', $url) - ->fields([ - 'Title' => 'Server Expenses', - 'Amount' => '$1,234', - 'Via' => 'American Express', - 'Was Overdue' => ':-1:', - ]); - }); - } - -The example above will create a Slack message that looks like the following: - - - - -### Routing Slack Notifications - -To route Slack notifications to the proper location, define a `routeNotificationForSlack` method on your notifiable entity. This should return the webhook URL to which the notification should be delivered. Webhook URLs may be generated by adding an "Incoming Webhook" service to your Slack team: - - slack_webhook_url; - } - } - - -## Notification Events - -When a notification is sent, the `Illuminate\Notifications\Events\NotificationSent` event is fired by the notification system. This contains the "notifiable" entity and the notification instance itself. You may register listeners for this event in your `EventServiceProvider`: - - /** - * The event listener mappings for the application. - * - * @var array - */ - protected $listen = [ - 'Illuminate\Notifications\Events\NotificationSent' => [ - 'App\Listeners\LogNotification', - ], - ]; - -> {tip} After registering listeners in your `EventServiceProvider`, use the `event:generate` Artisan command to quickly generate listener classes. - -Within an event listener, you may access the `notifiable`, `notification`, and `channel` properties on the event to learn more about the notification recipient or the notification itself: - - /** - * Handle the event. - * - * @param NotificationSent $event - * @return void - */ - public function handle(NotificationSent $event) - { - // $event->channel - // $event->notifiable - // $event->notification - } - - -## Custom Channels - -Laravel ships with a handful of notification channels, but you may want to write your own drivers to deliver notifications via other channels. Laravel makes it simple. To get started, define a class that contains a `send` method. The method should receive two arguments: a `$notifiable` and a `$notification`: - - toVoice($notifiable); - - // Send notification to the $notifiable instance... - } - } - -Once your notification channel class has been defined, you may simply return the class name from the `via` method of any of your notifications: - - ## Introduction -Packages are the primary way of adding functionality to Laravel. Packages might be anything from a great way to work with dates like [Carbon](https://github.com/briannesbitt/Carbon), or an entire BDD testing framework like [Behat](https://github.com/Behat/Behat). +Laravelတွင် တခြား functions တွေ အသစ်ထည့်တဲ့အခါမှာ Packages တွေခွဲပြီးအသစ်ထပ်ထည့်တဲ့နည်းက သမရိုးကျ နည်းလမ်းကောင်းတခုဖြစ်ပါတယ်။ လူအများစုဆောင်းပြီး project တွေကို ဖန်တီးရာတဲ့အခါမှာ အရမ်းအသုံးတည့်တဲ့နည်းလမ်းဖြစ်ပါတယ်။ ဥပမာ [Carbon](https://github.com/briannesbitt/Carbon), or [Behat](https://github.com/Behat/Behat). -Of course, there are different types of packages. Some packages are stand-alone, meaning they work with any PHP framework. Carbon and Behat are examples of stand-alone packages. Any of these packages may be used with Laravel by simply requesting them in your `composer.json` file. +သေချာတာပေါ့ဗျာ ၊ Packages တွေကို အသုံးပြုရာမှာ ပုံစံမျိုးစုံရှိပါတယ်။ တချိုဟာတွေက Laravel တစ်ခုတည်းမဟုတ်ပဲ အခြားခြားသော Framework တွေမှာပါ အလုပ်လုပ်တဲ့ stand-alone packages တွေဖြစ်တယ်။ အပေါ်က CarBon နဲ့ Behat လို packages တွေကတော့ Stand-alon တွေဖြစ်ပါတယ် ။ အဲဒီလိုဖန်တီးထားတဲ့ packages တွေကို Laravel မှာသုံးမယ်ဆိုရင်တော့ ထုံးစံတိုင်း "composer.json" ဖိုင်မှာ သွားထည့့်ပေးလိုက်တာနဲ့ သုံးပြုနိုင်မှာပါ။ -On the other hand, other packages are specifically intended for use with Laravel. These packages may have routes, controllers, views, and configuration specifically intended to enhance a Laravel application. This guide primarily covers the development of those packages that are Laravel specific. +တခြားတချက်ကတော့ တခြား packages တွေက Laravel အတွက်ပဲလို့ အသေသတ်မှတ်ပီး ထုတ်လုပ်ထားတဲ့ packages တွေလဲ ရှိပါတယ် ။ ဥပမာ အရင် laravel version တွေမှာ တုန်းက "bundles" လို packages တွေမျိုးပါ။ အဲဒီ packages တွေမှာ routes, controllers, views, configuration, နဲ့ migrations ဖွဲ့စည်းထားပြီး laravel ရဲ့ လုပ်ဆောင်နိုင်မူတွေကို တိုးချဲ့ အသုံးပြုနိုင်ပါတယ်။ Stan-alone packages တစ်ခု ဖန်တီးဖို့ဆိုတာ အရမ်းခက်တဲ့ ကိစ္စတော့မဟုတ်ပါဘူး ၊ အခုအောက်မှာ ထပ်ဖော်ပြမယ့် နည်းလမ်းတွေအတိုင်း ဖန်တီးကြည့်နိုင်ပါတယ်။ - -### A Note On Facades +Laravel အတွက် Packages တွေကို [Packagist](http://packagist.org)မှာတင်ပြီး ဖြန့်ချီနိုင်ပြီး [Composer](http://getcomposer.org) လို အရမ်းမိုက်တဲ့ Package destributuin tool တွေသုံးပြု ပြီး ဖန်တီးရမှာပါ။ -When writing a Laravel application, it generally does not matter if you use contracts or facades since both provide essentially equal levels of testability. However, when writing packages, it is best to use [contracts](/docs/{{version}}/contracts) instead of [facades](/docs/{{version}}/facades). Since your package will not have access to all of Laravel's testing helpers, it will be easier to mock or stub a contract than to mock a facade. + +## Creating A Package + +Laravel မှာသုံးပြုဖို့အတွက် packages တစ်ခုတည်ဆောက်ဖို့အတွက်ကတော့ 'workbench' Artisan command ကို အသုံးပြုပြီးလွယ်လွယ်ကူကူကိုဖန်တီးနိုင်ပါတယ်။ အဲလိုလုပ်ဖို့အတွက် ပထမဆုံး 'app/config/workbench.php' မှာ name နဲ့ email လေးအရင်သွားဖြည့်ပေးရပါတယ်။ အဲဒီ name နဲ့ email ကို အသစ်ဆောက်မယ့် packages တွေ က 'composer.json' မှာ ပြန်အသုံးပြုဖို့အတွက်ဖြစ်ပါတယ်။ကဲ့ ဒီလောက်ပြင်ဆင်ပြီးရင် package တစ်ခု တည်ဆောက်ဖို့ အဆင်သင့်ဖြစ်နေပါပြီ။အောက်က ကွန်မန်းကို Terminal(cmd) မှာ ထည့် run လိုက်ပါ။ + +#### Issuing The Workbench Artisan Command + + php artisan workbench vendor/package --resources + +အပေါ်က command ထဲမှာ vendor ဆိုတာက package တစ်ခုကို authors တွေခွဲရေးတဲ့အခါမှာ package name ကို ခွဲခွဲခြားခြားသိနိုင်အောင်ပေးထားတဲ့နာမည်ဖြစ်ပါတယ်။ Vendor ဆိုတာက အဲဒီ package ကို ဖန်တီးတဲ့လူဖြစ်ပြီး package ဆိုတာကတော့ ကိုယ်လုပ်တဲ့ package name ဖြစ်ပါတယ်။ ဥပမာ ကျွန်တော် Taylar Otwell က "Zapper" ဆိုတဲ့ package တစ်ခုတည်ဆောက်လိုက်ရင် Package name က 'Zapper' ဖြစ်ပြး Vendor name က Taylar ဖြစ်ပါတယ်။ပုံမှန်အားဖြင့်တော့ workbench က framework package တခုတည်ဆောက်ပါတယ်။ "--resources" command က workbench ကို `migrations`, `views`, `config`, စသဖြင့်လိုအပ်တဲ့ ဖိုင်တွေကို ဖန်တီးပေးဖို ့ပြောပါတယ်။ + +အပေါ်က 'Workbench' ကို run ပြီးပြီဆိုရင်တော့ ၊ ကိုယ်ပေးထားတဲ့ နာမည်အတိုင်းပဲ 'workbench' ဆိုတဲ့ဖိုဒါထဲမှာ vendor name နဲ့ ဖိုဒါတွေရောက်လာပြီး အထဲမှာ package နာမည်နဲ့ လိုအပ်တဲ့ဖိုင်တွေအကုန် အလိုလျောက်ရှိနေပါလိမ့်မယ်။ ပြီးရင်တော့ တည်ဆောက်လိုက်တဲ့ package ကို laravel ကနေ သုံးပြုနိုင်ရန်အတွက် 'ServiceProvider' ကြော်ငြာပေးရပါတယ်။ Service Provider ကို 'app/config/app.php' မှာ သွားထည့်ပေးရပါတယ်။အဲဒီမှာ သွားထည့်ပေးလိုက်ရင် workbench ထဲက package တွေကို laravel ကနေ အသုံးပြုနိုင်ပါပြီ။ Service Provider က '[Package]ServiceProvider' ကိုအသုံးပြုပါတယ်။ဥပမာအရဆိုရင် 'app/config/app.php' က Provider မှာ 'Taylor\Zapper\ZapperServiceProvider' ဆိုပြီး array ထဲမှာ သွားထည့်ပေးရမှာပါ။ + +အခုလို Provider မှာ သွားထည့်ပေးပြီးရင်တော့ packages ကို လိုအပ်သလိုမျိုး စတင် အသုံးပြုနိုပ်ပါပြီ။ ပထမဆုံး package structure နဲ ့ development workflow ကို အရင်လေ့လာသင့်ပါတယ်။ + +> **Note:** Service Provider cannot be found ဆိုပြီး error ပြနေရင် `php artisan dump-autoload` ကို root directory မှာ terminal(cmd) မှ တစ်ဆင့် run ပြီး ပြန်စမ်းကြည့်ပါ။ + + +## Package Structure + +'workbench' command ကို အသုံးပြုပြီးတဲ့အခါမှာ အဲဒီ command က ကိုယ်ဖန်တီးလိုက်တဲ့ packages ကို laravel နှင့် တွဲဖက်အသုံးပြုနိုင်အောင် အကုန်အလိုလျောက်ပြုလုပ်ပေးပါတယ်။ + +#### Basic Package Directory Structure + + /src + /Vendor + /Package + PackageServiceProvider.php + /config + /lang + /migrations + /views + /tests + /public + +အပေါ်က file structure ကိုအရင်လေ့လာကြည့်ရအောင်။ 'src/Vendor/Package' က တော့ 'ServiceProvider' ပါဝင်တဲ့အတွက် package's classes တွေရဲ့ အဓိကနေရာလို့ပြောရမှာပါ။ `config`, `lang`, `migrations`, နဲ့ `views' တွေကတော့ packages အတွက် လိုအပ်တဲ့ resources တွေပါဝင်မယ့်ဖိုင်တွေဖြစ်ပါတယ်။ +Packages တစ်ခုမှာလဲ Laravel မှာရှိတဲ့ resources တွေ အတိုင်း တည်ရှိနေမှာပါ။ ## Service Providers -[Service providers](/docs/{{version}}/providers) are the connection points between your package and Laravel. A service provider is responsible for binding things into Laravel's [service container](/docs/{{version}}/container) and informing Laravel where to load package resources such as views, configuration, and localization files. +Service providers ဖိုင်တွေကတော့ packages တွေရဲ့ အသက်ဖိုင်လို့ပြောရမှာပါ။ပုံမှန်အားဖြင့် Service Provider မှာ 'boot' နဲ့ 'register' ဆိုတဲ့ methodsနှစ်ခုပါဝင်ပါတယ်။ +ဒီ methods နှစ်ခုမှာပဲ အကုန်လုံးပြုလုပ်နိုင်ပါတယ်။ ဥပမာ routes ဖိုင်ချိတ်ဖို့ ၊IoC Container တွေ register bindings လုပ်ဖို့ ၊ events တွေထည့်ဖို့ ၊ အကုန်လုံးနည်းပါးကို ဒီ method နှစ်ခုတစ်ဆင့် အလုပ်လုပ်သွားမှာပါ။ + +"register" method က Service Provider ကို register ပြုလုပ်ပြီးတာနဲ့ အလုပ်လုပ်မယ့် method ဖြစ်ပါတယ်။ 'boot' method ကတော့ request အသက်မဝင်ခင်အချိန်ထိပဲ အလုပ်လုပ်မှာဖြစ်ပါတယ်။ ဒါဆိုရင်တော့ service provider ထဲက actions တွေ registe လုပ်ပြီးတဲ့အချိန် (သို ့) တခြား provider တစ်ခုရဲ့ service ကို ကျော်လွန်(override)အသုံးပြုလိုပါက 'boot' method ကို အသုံးပြုသင့်ပါတယ်။ + +'workbench' command နှင့် package တစ်ခုတည်ဆောက်လိုက်တာနဲ့ 'boot' method မှာ အောက်ဖော်ပြပါအတိုင်း action တစ်ခု ပါဝင်နေပါတယ်။ + + $this->package('vendor/package'); + +ဒီ method က laravel ကို packages ထဲက views,config, other resource တွေကို အသုံးပြုနိုင်အောင်လုပ်ပေးပါတယ်။ ပုံမှန်အားဖြင့်တော့ အဲဒီ ကုတ်ကို ပြုပြင်ဖို့မလိုအပ်ပါဘူး။ + +ပုံမှန်အားဖြင့် package တစ်ခုတည်ဆောက်ပြီးတဲ့အခါ အဲဒီ packages ရဲ့ resource တွေက 'vendor/package' အောက်မှာရှိပါတယ်။ဘယ်လိုဖြစ်ဖြစ် package method ကို argument နောက်တစ်ခု ထပ်ထည့်ပြီး package resource နေရာတွေကို လိုအပ်သလို အောက်ကပုံစံအတိုင်း ပြောင်းလဲနိုင်ပါသေးတယ်။ + + // Passing custom namespace to package method + $this->package('vendor/package', 'custom-namespace'); + + // Package resources now accessed via custom-namespace + $view = View::make('custom-namespace::foo'); + +Service provider classes တွေအတွက် app directory ထဲမှာ နေရာအတည်တစ်ကျ သတ်မှတ်ထားတာမျိုးလဲမရှိပါဘူး။ 'app' ထဲမှ 'Providers' namespace ပေးပြီး ထားချင်တဲ့နေရာမှာ ထားနိုင်ပါတယ်။ ဒဲဒီ class ဖိုင်တွေကို Composer's [auto-loading facilities](http://getcomposer.org/doc/01-basic-usage.md#autoloading) က သိမှတ်ပြုနေသ၍ အဲဒီ class ဖိုင်ထဲက class တွေကို app က ယူသုံးနိုင်မှာပါ။ + +'Package ထဲက resources ( ဥပမာ Configuration ၊ Views ) နေရာတွေကို ပြောင်းလိုက်ပြီဆိုရင် ပြောင်းလိုက်တဲ့နေရာကို 'package' methord မှာ တတိယမြောက် argument တစ်ခုအဖြစ် အောက်ပါအတိုင်းထည့်သင့်ပေးသင့်ပါတယ်။ + + $this->package('vendor/package', null, '/path/to/resources'); + + +## Deferred Providers + + +If you are writing a service provider that does not register any resources such as configuration or views, you may choose to make your provider "deferred". A deferred service provider is only loaded and registered when one of the services it provides is actually needed by the application IoC container. If none of the provider's services are needed for a given request cycle, the provider is never loaded. + +To defer the execution of your service provider, set the `defer` property on the provider to `true`: + + protected $defer = true; + +Next you should override the `provides` method from the base `Illuminate\Support\ServiceProvider` class and return an array of all of the bindings that your provider adds to the IoC container. For example, if your provider registers `package.service` and `package.another-service` in the IoC container, your `provides` method should look like this: + + public function provides() + { + return array('package.service', 'package.another-service'); + } + + +## Package Conventions + + +When utilizing resources from a package, such as configuration items or views, a double-colon syntax will generally be used: + +#### Loading A View From A Package + + return View::make('package::view.name'); + +#### Retrieving A Package Configuration Item + + return Config::get('package::group.option'); + +> **Note:** If your package contains migrations, consider prefixing the migration name with your package name to avoid potential class name conflicts with other packages. + + +## Development Workflow + + +When developing a package, it is useful to be able to develop within the context of an application, allowing you to easily view and experiment with your templates, etc. So, to get started, install a fresh copy of the Laravel framework, then use the `workbench` command to create your package structure. + +After the `workbench` command has created your package. You may `git init` from the `workbench/[vendor]/[package]` directory and `git push` your package straight from the workbench! This will allow you to conveniently develop the package in an application context without being bogged down by constant `composer update` commands. + +Since your packages are in the `workbench` directory, you may be wondering how Composer knows to autoload your package's files. When the `workbench` directory exists, Laravel will intelligently scan it for packages, loading their Composer autoload files when the application starts! + +If you need to regenerate your package's autoload files, you may use the `php artisan dump-autoload` command. This command will regenerate the autoload files for your root project, as well as any workbenches you have created. + +#### Running The Artisan Autoload Command + + php artisan dump-autoload + + +## Package Routing + +In prior versions of Laravel, a `handles` clause was used to specify which URIs a package could respond to. However, in Laravel 4, a package may respond to any URI. To load a routes file for your package, simply `include` it from within your service provider's `boot` method. + +#### Including A Routes File From A Service Provider + + public function boot() + { + $this->package('vendor/package'); + + include __DIR__.'/../../routes.php'; + } + +> **Note:** If your package is using controllers, you will need to make sure they are properly configured in your `composer.json` file's auto-load section. + + +## Package Configuration + +#### Accessing Package Configuration Files + +Some packages may require configuration files. These files should be defined in the same way as typical application configuration files. And, when using the default `$this->package` method of registering resources in your service provider, may be accessed using the usual "double-colon" syntax: + + Config::get('package::file.option'); + +#### Accessing Single File Package Configuration + +However, if your package contains a single configuration file, you may simply name the file `config.php`. When this is done, you may access the options directly, without specifying the file name: + + Config::get('package::option'); + +#### Registering A Resource Namespace Manually + +Sometimes, you may wish to register package resources such as views outside of the typical `$this->package` method. Typically, this would only be done if the resources were not in a conventional location. To register the resources manually, you may use the `addNamespace` method of the `View`, `Lang`, and `Config` classes: + + View::addNamespace('package', __DIR__.'/path/to/views'); + +Once the namespace has been registered, you may use the namespace name and the "double colon" syntax to access the resources: + + return View::make('package::view.name'); + +The method signature for `addNamespace` is identical on the `View`, `Lang`, and `Config` classes. + +### Cascading Configuration Files + +When other developers install your package, they may wish to override some of the configuration options. However, if they change the values in your package source code, they will be overwritten the next time Composer updates the package. Instead, the `config:publish` artisan command should be used: + + php artisan config:publish vendor/package -A service provider extends the `Illuminate\Support\ServiceProvider` class and contains two methods: `register` and `boot`. The base `ServiceProvider` class is located in the `illuminate/support` Composer package, which you should add to your own package's dependencies. To learn more about the structure and purpose of service providers, check out [their documentation](/docs/{{version}}/providers). +When this command is executed, the configuration files for your application will be copied to `app/config/packages/vendor/package` where they can be safely modified by the developer! - -## Routing - -To define routes for your package, simply `require` the routes file from within your package service provider's `boot` method. From within your routes file, you may use the `Illuminate\Support\Facades\Route` facade to [register routes](/docs/{{version}}/routing) just as you would within a typical Laravel application: - - /** - * Perform post-registration booting of services. - * - * @return void - */ - public function boot() - { - if (! $this->app->routesAreCached()) { - require __DIR__.'/../../routes.php'; - } - } +> **Note:** The developer may also create environment specific configuration files for your package by placing them in `app/config/packages/vendor/package/environment`. - -## Resources + +## Package Views - -### Configuration - -Typically, you will need to publish your package's configuration file to the application's own `config` directory. This will allow users of your package to easily override your default configuration options. To allow your configuration files to be published, call the `publishes` method from the `boot` method of your service provider: - - /** - * Perform post-registration booting of services. - * - * @return void - */ - public function boot() - { - $this->publishes([ - __DIR__.'/path/to/config/courier.php' => config_path('courier.php'), - ]); - } +If you are using a package in your application, you may occasionally wish to customize the package's views. You can easily export the package views to your own `app/views` directory using the `view:publish` Artisan command: -Now, when users of your package execute Laravel's `vendor:publish` command, your file will be copied to the specified publish location. Of course, once your configuration has been published, its values may be accessed like any other configuration file: + php artisan view:publish vendor/package - $value = config('courier.option'); +This command will move the package's views into the `app/views/packages` directory. If this directory doesn't already exist, it will be created when you run the command. Once the views have been published, you may tweak them to your liking! The exported views will automatically take precedence over the package's own view files. -#### Default Package Configuration + +## Package Migrations -You may also merge your own package configuration file with the application's published copy. This will allow your users to define only the options they actually want to override in the published copy of the configuration. To merge the configurations, use the `mergeConfigFrom` method within your service provider's `register` method: +#### Creating Migrations For Workbench Packages - /** - * Register bindings in the container. - * - * @return void - */ - public function register() - { - $this->mergeConfigFrom( - __DIR__.'/path/to/config/courier.php', 'courier' - ); - } +You may easily create and run migrations for any of your packages. To create a migration for a package in the workbench, use the `--bench` option: - -### Migrations + php artisan migrate:make create_users_table --bench="vendor/package" -If your package contains [database migrations](/docs/{{version}}/migrations), you may use the `loadMigrationsFrom` method to inform Laravel how to load them. The `loadMigrationsFrom` method accepts the path to your package's migrations as its only argument: +#### Running Migrations For Workbench Packages - /** - * Perform post-registration booting of services. - * - * @return void - */ - public function boot() - { - $this->loadMigrationsFrom(__DIR__.'/path/to/migrations'); - } - -Once your package's migrations have been registered, they will automatically be run when the `php artisan migrate` command is executed. You do not need to export them to the application's main `database/migrations` directory. - - -### Translations + php artisan migrate --bench="vendor/package" -If your package contains [translation files](/docs/{{version}}/localization), you may use the `loadTranslationsFrom` method to inform Laravel how to load them. For example, if your package is named `courier`, you should add the following to your service provider's `boot` method: +#### Running Migrations For An Installed Package - /** - * Perform post-registration booting of services. - * - * @return void - */ - public function boot() - { - $this->loadTranslationsFrom(__DIR__.'/path/to/translations', 'courier'); - } +Packages ထဲမှာ database migrate လုပ်ဖို့အတွက် workbench ထဲမှာ +To run migrations for a finished package that was installed via Composer into the `vendor` directory, you may use the `--package` directive: -Package translations are referenced using the `package::file.line` syntax convention. So, you may load the `courier` package's `welcome` line from the `messages` file like so: - - echo trans('courier::messages.welcome'); - -#### Publishing Translations - -If you would like to publish your package's translations to the application's `resources/lang/vendor` directory, you may use the service provider's `publishes` method. The `publishes` method accepts an array of package paths and their desired publish locations. For example, to publish the translation files for the `courier` package, you may do the following: - - /** - * Perform post-registration booting of services. - * - * @return void - */ - public function boot() - { - $this->loadTranslationsFrom(__DIR__.'/path/to/translations', 'courier'); - - $this->publishes([ - __DIR__.'/path/to/translations' => resource_path('lang/vendor/courier'), - ]); - } - -Now, when users of your package execute Laravel's `vendor:publish` Artisan command, your package's translations will be published to the specified publish location. - - -### Views - -To register your package's [views](/docs/{{version}}/views) with Laravel, you need to tell Laravel where the views are located. You may do this using the service provider's `loadViewsFrom` method. The `loadViewsFrom` method accepts two arguments: the path to your view templates and your package's name. For example, if your package's name is `courier`, you would add the following to your service provider's `boot` method: - - /** - * Perform post-registration booting of services. - * - * @return void - */ - public function boot() - { - $this->loadViewsFrom(__DIR__.'/path/to/views', 'courier'); - } - -Package views are referenced using the `package::view` syntax convention. So, once your view path is registered in a service provider, you may load the `admin` view from the `courier` package like so: - - Route::get('admin', function () { - return view('courier::admin'); - }); + php artisan migrate --package="vendor/package" -#### Overriding Package Views + +## Package Assets -When you use the `loadViewsFrom` method, Laravel actually registers two locations for your views: the application's `resources/views/vendor` directory and the directory you specify. So, using the `courier` example, Laravel will first check if a custom version of the view has been provided by the developer in `resources/views/vendor/courier`. Then, if the view has not been customized, Laravel will search the package view directory you specified in your call to `loadViewsFrom`. This makes it easy for package users to customize / override your package's views. +#### Moving Package Assets To Public +'packages' တွေမှာ 'Javascript, Css, images လို assets တွေပါကောင်းပါနိုင်ပါတယ်။ အဲဒီ assets တွေကို app မှ တဆင့်တန်းဆွဲခေါ်သုံးဖို့မဖြစ်နိုင်ပါဘူး ။ အဲဒီအတွက် 'package' ထဲက assets တွေကို public အောက်ကို ပြောင်းထည့်ပေးဖို့လိုအပ်ပါတယ်။ အဲဒီအတွက် `asset:publish` ကွန်မန်း ကို အောက်ကအတိုင်း အသုံးပြုပြီး ပြောင်းထည့်ပေးနိုင်ပါတယ်။ -#### Publishing Views - -If you would like to make your views available for publishing to the application's `resources/views/vendor` directory, you may use the service provider's `publishes` method. The `publishes` method accepts an array of package view paths and their desired publish locations: - - /** - * Perform post-registration booting of services. - * - * @return void - */ - public function boot() - { - $this->loadViewsFrom(__DIR__.'/path/to/views', 'courier'); - - $this->publishes([ - __DIR__.'/path/to/views' => resource_path('views/vendor/courier'), - ]); - } + php artisan asset:publish -Now, when users of your package execute Laravel's `vendor:publish` Artisan command, your package's views will be copied to the specified publish location. + php artisan asset:publish vendor/package - -## Public Assets +တကယ်လို တည်ဆောက်ထားတဲ့ 'package' က 'workbench' အောက်မှာပဲရှိသေးရင်တော့ ' --bench ' ကိုအောက်ပါအတိုင်းထပ်ထည့်ပြီးရေးပေးရပါတယ်။ -Your package may have assets such as JavaScript, CSS, and images. To publish these assets to the application's `public` directory, use the service provider's `publishes` method. In this example, we will also add a `public` asset group tag, which may be used to publish groups of related assets: - - /** - * Perform post-registration booting of services. - * - * @return void - */ - public function boot() - { - $this->publishes([ - __DIR__.'/path/to/assets' => public_path('vendor/courier'), - ], 'public'); - } + php artisan asset:publish --bench="vendor/package" -Now, when your package's users execute the `vendor:publish` command, your assets will be copied to the specified publish location. Since you will typically need to overwrite the assets every time the package is updated, you may use the `--force` flag: +ဒီကွန်မန်းက package ထဲမှ assets တွေကို 'public/packages' ထဲကို သက်ဆိုင်ရင် package နဲ့ vendor နာမည်တွေအလိုက်ဖိုဒါတွေ အလိုလျောက်ဆောက်ပြီး သိမ်းဆည်းပေးသွားမှာပါ။ ဥပမာ 'workbench' အောက်မှာ 'usersape/kusod' ဆိုပြီး packages ဆောက်ထားရင် 'public/packages/userscape/kudos' ဆိုပြီး ရောက်သွားမှာပါ။ ဒီလိုလုပ်ခြင်းအားဖြင့် asset တွေနဲ့ပက်သက်ပြီး လုံခြုံရေးဆိုင်ရာ အားသာချက်များ ရရှိနိုင်ပါတယ်။ - php artisan vendor:publish --tag=public --force + +## Publishing Packages - -## Publishing File Groups +ကိုယ်တည်ဆောက်ထားတဲ့'Package' က အသုံးပြုဖို ့အားလုံးပြင်ဆင်ပြီးသွားရင်တော့ [Packagist](http://packagist.org) ကို တခြားသူတွေပါသုံးပြုနိုင်အောင် တင်ထားပေးသင့်ပါတယ်။ တကယ်လို့ ကိုယ် တည်ဆောက်လိုက်တဲ့ 'package' က laravel အတွက်ပဲ သီးသန့်တည်ဆောက်ထားရင်တော့ 'composer.json' မှာ 'laravel' ဆိုပြီး tag ထည့်ပေးဖို့လိုအပ်ပါတယ်။ -You may want to publish groups of package assets and resources separately. For instance, you might want to allow your users to publish your package's configuration files without being forced to publish your package's assets. You may do this by "tagging" them when calling the `publishes` method from a package's service provider. For example, let's use tags to define two publish groups in the `boot` method of a package service provider: - /** - * Perform post-registration booting of services. - * - * @return void - */ - public function boot() - { - $this->publishes([ - __DIR__.'/../config/package.php' => config_path('package.php') - ], 'config'); +Also, it is courteous and helpful to tag your releases so that developers can depend on stable versions when requesting your package in their `composer.json` files. If a stable version is not ready, consider using the `branch-alias` Composer directive. - $this->publishes([ - __DIR__.'/../database/migrations/' => database_path('migrations') - ], 'migrations'); - } - -Now your users may publish these groups separately by referencing their tag when executing the `vendor:publish` command: +Once your package has been published, feel free to continue developing it within the application context created by `workbench`. This is a great way to continue to conveniently develop the package even after it has been published. - php artisan vendor:publish --tag="config" +Some organizations choose to host their own private repository of packages for their own developers. If you are interested in doing this, review the documentation for the [Satis](http://github.com/composer/satis) project provided by the Composer team. diff --git a/pagination.md b/pagination.md old mode 100644 new mode 100755 index 77444c2..f87f16c --- a/pagination.md +++ b/pagination.md @@ -1,179 +1,140 @@ # Pagination -- [Introduction](#introduction) -- [Basic Usage](#basic-usage) - - [Paginating Query Builder Results](#paginating-query-builder-results) - - [Paginating Eloquent Results](#paginating-eloquent-results) - - [Manually Creating A Paginator](#manually-creating-a-paginator) -- [Displaying Pagination Results](#displaying-pagination-results) - - [Converting Results To JSON](#converting-results-to-json) -- [Customizing The Pagination View](#customizing-the-pagination-view) -- [Paginator Instance Methods](#paginator-instance-methods) +- [ပြင်ဆင်ခြင်း](#configuration) +- [အသုံးအနှုန်း](#usage) +- [Appending To Pagination Links](#appending-to-pagination-links) +- [Converting To JSON](#converting-to-json) +- [Custom Presenters](#custom-presenters) - -## Introduction + +## ပြင်ဆင်ခြင်း -In other frameworks, pagination can be very painful. Laravel's paginator is integrated with the [query builder](/docs/{{version}}/queries) and [Eloquent ORM](/docs/{{version}}/eloquent) and provides convenient, easy-to-use pagination of database results out of the box. The HTML generated by the paginator is compatible with the [Bootstrap CSS framework](http://getbootstrap.com/). +Frameworks တော်တော်များများအတွက်တော့ pagination ပြုလုပ်ဖို့အတွက် စိတ်ပျက်စရာ ကိစ္စတွေ ကြုံတွေ့နိုင်ပါတယ်။ Laravel ကတော့ ဒီကိစ္စကို လွယ်လွယ်ကူကူ ပဲပြုလုပ်နိုင်အောင် အဆင်သင့် ပြင်ဆင်ထားပေးပါတယ်။`app/config/view.php` ဖိုင်ထဲမှာ pagination အတွက် option တစ်ခု ပါရှိပါတယ်။ အဲ့ဒီ `pagination` option မှာ pagination links တွေအတွက် ဘယ် view ကိုအသုံးပြုသင့်တယ်ဆိုတာကို သတ်မှတ်ပေးထားနိုင်ပါတယ်။ ပုံမှန်အတိုင်းဆိုရင်တော့ Laravel မှာ pagination အတွက် view နှစ်ခုကို သတ်မှတ်ပေးထားပါတယ်။ - -## Basic Usage +`pagination::slider` ကိုအသုံးပြုမယ်ဆိုရင် လက်ရှိ view မှာဖော်ပြထားတဲ့ items အရေအတွက်ကိုအခြေခံပီးတော့ links တွေထုတ်ပေးပါတယ်။ `pagination::simple` view ကတော့ "previous" နဲ့ "next" button နှစ်ခုထုတ်ပေးပါတယ်။ အဲ့ဒီ view နှစ်ခုစလုံးဟာ Twitter Bootstrap နဲ့ အဆင်ပြေပြေတွဲဖက်အသုံးပြုနိုင်ပါတယ်။ - -### Paginating Query Builder Results + +## အသုံးအနှုန်း -There are several ways to paginate items. The simplest is by using the `paginate` method on the [query builder](/docs/{{version}}/queries) or an [Eloquent query](/docs/{{version}}/eloquent). The `paginate` method automatically takes care of setting the proper limit and offset based on the current page being viewed by the user. By default, the current page is detected by the value of the `page` query string argument on the HTTP request. Of course, this value is automatically detected by Laravel, and is also automatically inserted into links generated by the paginator. +အချက်အလက်တွေကို paginate လုပ်လုပ်ဖို့အတွက် နည်းနည်းတွေ အများကြီးရှိပါတယ်။ အဲ့ဒီအထဲကမှ `paginate` method ကို Laravel ရဲ့ Query Builder သို့မဟုတ် Eloquent Model တွေနဲ့တဲသုံးတဲ့နည်းကတော့ အရိုးရှင်းဆုံးနည်းလမ်းဖြစ်ပါတယ်။ -In this example, the only argument passed to the `paginate` method is the number of items you would like displayed "per page". In this case, let's specify that we would like to display `15` items per page: +#### Paginating Database Results - paginate(15); - namespace App\Http\Controllers; +#### Paginating An Eloquent Model - use Illuminate\Support\Facades\DB; - use App\Http\Controllers\Controller; +[Eloquent](eloquent.md) models တွေကိုလည်း paginate လုပ်နိုင်ပါတယ် - - class UserController extends Controller - { - /** - * Show all of the users for the application. - * - * @return Response - */ - public function index() - { - $users = DB::table('users')->paginate(15); + $allUsers = User::paginate(15); - return view('user.index', ['users' => $users]); - } - } + $someUsers = User::where('votes', '>', 100)->paginate(15); -> {note} Currently, pagination operations that use a `groupBy` statement cannot be executed efficiently by Laravel. If you need to use a `groupBy` with a paginated result set, it is recommended that you query the database and create a paginator manually. - -#### "Simple Pagination" +`paginate` method ကို passing ပေးလိုက်တဲ့ argument(number) ဟာ စာမျက်နှာတစ်ခုပေါ်မှာ အချက်အလက် ဘယ်လောက်ပေါ်မယ်ဆိုတဲ့ အရေအတွက်ဖြစ်ပါတယ်။ Pagination links တွေကို view မှာပြန်ပြဖို့အတွက်တော့ `links` method ကိုအသုံးပြုနိုင်ပါတယ်။ -If you only need to display simple "Next" and "Previous" links in your pagination view, you may use the `simplePaginate` method to perform a more efficient query. This is very useful for large datasets when you do not need to display a link for each page number when rendering your view: +
    + + name; ?> + +
    - $users = DB::table('users')->simplePaginate(15); + links(); ?> - -### Paginating Eloquent Results +လက်ရှိ စာမျက်နှာနဲ့ပတ်သက်ပြီး framework ကို ဘာပြင်ဆင်မှုမှ မလုပ်ခဲ့တာကို သတိပြုမိမှာပါ။ အဲ့ဒီအတွက် laravel က အလိုအလျောက်ဆုံးဖြတ်ပေးပါတယ်။ -You may also paginate [Eloquent](/docs/{{version}}/eloquent) queries. In this example, we will paginate the `User` model with `15` items per page. As you can see, the syntax is nearly identical to paginating query builder results: +Pagination အတွက် custom view ကိုအသုံးပြုချင်ရင်တော့ `links` method ထဲမှာ view ကို passing ပေးလိုက်ရုံပါပဲ။ - $users = App\User::paginate(15); + links('view.name'); ?> -Of course, you may call `paginate` after setting other constraints on the query, such as `where` clauses: +Pagination information တွေကိုလဲ အောက်ပါ methods တွေကိုအသုံးပြုပြီး ရယူနိုင်ပါတယ်။ - $users = User::where('votes', '>', 100)->paginate(15); +- `getCurrentPage` +- `getLastPage` +- `getPerPage` +- `getTotal` +- `getFrom` +- `getTo` +- `count` -You may also use the `simplePaginate` method when paginating Eloquent models: - $users = User::where('votes', '>', 100)->simplePaginate(15); +#### "Simple Pagination" - -### Manually Creating A Paginator +အကယ်၍ pagination view မှာ "next" နဲ့ "previous" links တွေကိုပဲပြချင်ရင်တော့ ပိုပြီးအဆင်ပြေတဲ့ query ကိုပြုလုပ်ပေးနိုင်တဲ့ `simplePaginate` method ကိုအသုံးပြုနိုင်ပါတယ်။ view မှာ page numbers တွေအတိအကျဖော်ပြစရာမလိုတဲ့အတွက် data တွေအများကြီးကို paginate လုပ်ရာမှာ ပိုမို အဆင်ပြေစေပါတယ်။ -Sometimes you may wish to create a pagination instance manually, passing it an array of items. You may do so by creating either an `Illuminate\Pagination\Paginator` or `Illuminate\Pagination\LengthAwarePaginator` instance, depending on your needs. + $someUsers = User::where('votes', '>', 100)->simplePaginate(15); -The `Paginator` class does not need to know the total number of items in the result set; however, because of this, the class does not have methods for retrieving the index of the last page. The `LengthAwarePaginator` accepts almost the same arguments as the `Paginator`; however, it does require a count of the total number of items in the result set. +#### Creating A Paginator Manually -In other words, the `Paginator` corresponds to the `simplePaginate` method on the query builder and Eloquent, while the `LengthAwarePaginator` corresponds to the `paginate` method. +အကယ်၍ pagination ကို manually ပြုလုပ်ချင်ရင် `Paginator::make` method ကိုအသုံးပြုနိုင်ပါတယ်။ -> {note} When manually creating a paginator instance, you should manually "slice" the array of results you pass to the paginator. If you're unsure how to do this, check out the [array_slice](http://php.net/manual/en/function.array-slice.php) PHP function. + $paginator = Paginator::make($items, $totalItems, $perPage); - -## Displaying Pagination Results +#### Customizing The Paginator URI -When calling the `paginate` method, you will receive an instance of `Illuminate\Pagination\LengthAwarePaginator`. When calling the `simplePaginate` method, you will receive an instance of `Illuminate\Pagination\Paginator`. These objects provide several methods that describe the result set. In addition to these helpers methods, the paginator instances are iterators and may be looped as an array. So, once you have retrieved the results, you may display the results and render the page links using [Blade](/docs/{{version}}/blade): +Paginator ကအသုံးပြုတဲ့ URI ကိုလဲ `setBaseUrl` method ကိုအသုံးပြုပြီး ပြင်ဆင်နိုင်ပါတယ်။ -
    - @foreach ($users as $user) - {{ $user->name }} - @endforeach -
    + $users = User::paginate(); - {{ $users->links() }} + $users->setBaseUrl('custom/url'); -The `links` method will render the links to the rest of the pages in the result set. Each of these links will already contain the proper `page` query string variable. Remember, the HTML generated by the `links` method is compatible with the [Bootstrap CSS framework](https://getbootstrap.com). +အပေါ်မှာပြထားတဲ့ ဥပမာအရဆိုရင် pagination URLs ဟာ http://example.com/custom/url?page=2 ပုံစံဖြစ်သွားမှာပါ။ -#### Customizing The Paginator URI + +## Appending To Pagination Links -The `setPath` method allows you to customize the URI used by the paginator when generating links. For example, if you want the paginator to generate links like `http://example.com/custom/url?page=N`, you should pass `custom/url` to the `setPath` method: +သင့်အနေနဲ့ `appends` method ကိုအသုံးပြုပြီး query string တွေကို pagination links တွေဆီကို ထပ်ပေါင်းထည့်လို့ရပါတယ်။ - Route::get('users', function () { - $users = App\User::paginate(15); + appends(array('sort' => 'votes'))->links(); ?> - $users->setPath('custom/url'); +အပေါ်မှာရေးထားတဲ့ အတိုင်းဆိုရင် URLs ဟာ အောက်ပါပုံစံနဲ့ထွက်လာမှာပါ။ - // - }); + http://example.com/something?page=2&sort=votes -#### Appending To Pagination Links +Paginator's URLs မှာ "hash fragment" ထပ်ပေါင်းထည့်ချင်ရင်တော့ `fragment` method ကိုအသုံးပြုနိုင်ပါတယ်။ -You may append to the query string of pagination links using the `appends` method. For example, to append `sort=votes` to each pagination link, you should make the following call to `appends`: + fragment('foo')->links(); ?> - {{ $users->appends(['sort' => 'votes'])->links() }} +အပေါ်က mehtod call ဟာ URLs ကို အောက်ပါအတိုင်းထုတ်ပေးပါလိမ့်မယ်။ -If you wish to append a "hash fragment" to the paginator's URLs, you may use the `fragment` method. For example, to append `#foo` to the end of each pagination link, make the following call to the `fragment` method: + http://example.com/something?page=2#foo - {{ $users->fragment('foo')->links() }} + +## Converting To JSON - -### Converting Results To JSON +The `Paginator` class implements the `Illuminate\Support\Contracts\JsonableInterface` contract and exposes the `toJson` method. You can may also convert a `Paginator` instance to JSON by returning it from a route. The JSON'd form of the instance will include some "meta" information such as `total`, `current_page`, `last_page`, `from`, and `to`. The instance's data will be available via the `data` key in the JSON array. -The Laravel paginator result classes implement the `Illuminate\Contracts\Support\JsonableInterface` contract and expose the `toJson` method, so it's very easy to convert your pagination results to JSON. You may also convert a paginator instance to JSON by simply returning it from a route or controller action: + +## Custom Presenters - Route::get('users', function () { - return App\User::paginate(); - }); +Pagination ရဲ့ UI style ဟာ default အနေအထားမှာ Bootstrap Frontend Framework က pagination ပုံစံအတိုင်းပြုလုပ်ပေးထားပါတယ်။ သင့်အနေနဲ့ customize presenter နဲ့ အသုံးပြုချင်တယ်ဆိုရင်လဲ အသုံးပြုလို့ရနိုင်ပါတယ်။ -The JSON from the paginator will include meta information such as `total`, `current_page`, `last_page`, and more. The actual result objects will be available via the `data` key in the JSON array. Here is an example of the JSON created by returning a paginator instance from a route: +### Extending The Abstract Presenter - { - "total": 50, - "per_page": 15, - "current_page": 1, - "last_page": 4, - "next_page_url": "http://laravel.app?page=2", - "prev_page_url": null, - "from": 1, - "to": 15, - "data":[ - { - // Result Object - }, - { - // Result Object - } - ] - } +`Illuminate\Pagination\Presenter` class ကို extend လုပ်ပြီး အဲ့ဒီ class ရဲ့ abstract methods တွေကို implement ပြုလုပ်ပြီးပြောငး်လဲ အသုံးပြုနိုင်ပါတယ်။ အောက်မှာ ပြထားတဲ့ ဥပမာကတော့ Zurb Foundation ရဲ့ ပုံစံကိုပြောင်းလဲ အသုံးပြုထားတာဖြစ်ပါတယ်။ - -## Customizing The Pagination View + class ZurbPresenter extends Illuminate\Pagination\Presenter { -By default, the views rendered to display the pagination links are compatible with the Bootstrap CSS framework. However, if you are not using Bootstrap, you are free to define your own views to render these links. When calling the `links` method on a paginator instance, pass the view name as the first argument to the method: - - {{ $paginator->links('view.name') }} + public function getActivePageWrapper($text) + { + return '
  • '.$text.'
  • '; + } -However, the easiest way to customize the pagination views is by exporting them to your `resources/views/vendor` directory using the `vendor:publish` command: + public function getDisabledTextWrapper($text) + { + return '
  • '.$text.'
  • '; + } - php artisan vendor:publish --tag=laravel-pagination + public function getPageLinkWrapper($url, $page) + { + return '
  • '.$page.'
  • '; + } -This command will place the views in the `resources/views/vendor/pagination` directory. The `default.blade.php` file within this directory corresponds to the default pagination view. Simply edit this file to modify the pagination HTML. + } - -## Paginator Instance Methods +### Using The Custom Presenter -Each paginator instance provides additional pagination information via the following methods: +ပထမဦးဆုံး custom presenter ပြုလုပ်လို့တဲ့ view ဖိုင်ကို `app/views` အောက်မှာ ပြုလုပ်ပေးလိုက်ပါ။ ပြီးရင် `app/config/view.php` အောက်မှာရှိတဲ့ `pagination` `pagination::slider-3` နေရာမှာ အသစ်လုပ်ထားတဲ့ view file ရဲ့ name နဲ့အစားထိုးလိုက်ပါ။ အပေါ်မှာပြထားတဲ့ Zurb Foundation အတိုင်းဆိုရင် သင့်ရဲ့ view ဖိုင်အသစ်ဟာ အောက်ပါ ပုံစံအတိုင်းဖြစ်ရမှာပါ။ -- `$results->count()` -- `$results->currentPage()` -- `$results->firstItem()` -- `$results->hasMorePages()` -- `$results->lastItem()` -- `$results->lastPage() (Not available when using simplePaginate)` -- `$results->nextPageUrl()` -- `$results->perPage()` -- `$results->previousPageUrl()` -- `$results->total() (Not available when using simplePaginate)` -- `$results->url($page)` + diff --git a/passwords.md b/passwords.md deleted file mode 100644 index 51535b9..0000000 --- a/passwords.md +++ /dev/null @@ -1,79 +0,0 @@ -# Resetting Passwords - -- [Introduction](#introduction) -- [Database Considerations](#resetting-database) -- [Routing](#resetting-routing) -- [Views](#resetting-views) -- [After Resetting Passwords](#after-resetting-passwords) -- [Customization](#password-customization) - - -## Introduction - -> {tip} **Want to get started fast?** Just run `php artisan make:auth` in a fresh Laravel application and navigate your browser to `http://your-app.dev/register` or any other URL that is assigned to your application. This single command will take care of scaffolding your entire authentication system, including resetting passwords! - -Most web applications provide a way for users to reset their forgotten passwords. Rather than forcing you to re-implement this on each application, Laravel provides convenient methods for sending password reminders and performing password resets. - -> {note} Before using the password reset features of Laravel, your user must use the `Illuminate\Notifications\Notifiable` trait. - - -## Database Considerations - -To get started, verify that your `App\User` model implements the `Illuminate\Contracts\Auth\CanResetPassword` contract. Of course, the `App\User` model included with the framework already implements this interface, and uses the `Illuminate\Auth\Passwords\CanResetPassword` trait to include the methods needed to implement the interface. - -#### Generating The Reset Token Table Migration - -Next, a table must be created to store the password reset tokens. The migration for this table is included with Laravel out of the box, and resides in the `database/migrations` directory. So, all you need to do is run your database migrations: - - php artisan migrate - - -## Routing - -Laravel includes `Auth\ForgotPasswordController` and `Auth\ResetPasswordController` classes that contains the logic necessary to e-mail password reset links and reset user passwords. All of the routes needed to perform password resets may be generated using the `make:auth` Artisan command: - - php artisan make:auth - - -## Views - -Again, Laravel will generate all of the necessary views for password reset when the `make:auth` command is executed. These views are placed in `resources/views/auth/passwords`. You are free to customize them as needed for your application. - - -## After Resetting Passwords - -Once you have defined the routes and views to reset your user's passwords, you may simply access the route in your browser at `/password/reset`. The `ForgotPasswordController` included with the framework already includes the logic to send the password reset link e-mails, while the `ResetPasswordController` includes the logic to reset user passwords. - -After a password is reset, the user will automatically be logged into the application and redirected to `/home`. You can customize the post password reset redirect location by defining a `redirectTo` property on the `ResetPasswordController`: - - protected $redirectTo = '/dashboard'; - -> {note} By default, password reset tokens expire after one hour. You may change this via the password reset `expire` option in your `config/auth.php` file. - - -## Customization - -#### Authentication Guard Customization - -In your `auth.php` configuration file, you may configure multiple "guards", which may be used to define authentication behavior for multiple user tables. You can customize the included `ResetPasswordController` to use the guard of your choice by overriding the `guard` method on the controller. This method should return a guard instance: - - use Illuminate\Support\Facades\Auth; - - protected function guard() - { - return Auth::guard('guard-name'); - } - -#### Password Broker Customization - -In your `auth.php` configuration file, you may configure multiple password "brokers", which may be used to reset passwords on multiple user tables. You can customize the included `ForgotPasswordController` and `ResetPasswordController` to use the broker of your choice by overriding the `broker` method: - - /** - * Get the broker to be used during password reset. - * - * @return PasswordBroker - */ - protected function broker() - { - return Password::broker('name'); - } diff --git a/providers.md b/providers.md deleted file mode 100644 index f8107c8..0000000 --- a/providers.md +++ /dev/null @@ -1,160 +0,0 @@ -# Service Providers - -- [Introduction](#introduction) -- [Writing Service Providers](#writing-service-providers) - - [The Register Method](#the-register-method) - - [The Boot Method](#the-boot-method) -- [Registering Providers](#registering-providers) -- [Deferred Providers](#deferred-providers) - - -## Introduction - -Service providers are the central place of all Laravel application bootstrapping. Your own application, as well as all of Laravel's core services are bootstrapped via service providers. - -But, what do we mean by "bootstrapped"? In general, we mean **registering** things, including registering service container bindings, event listeners, middleware, and even routes. Service providers are the central place to configure your application. - -If you open the `config/app.php` file included with Laravel, you will see a `providers` array. These are all of the service provider classes that will be loaded for your application. Of course, many of these are "deferred" providers, meaning they will not be loaded on every request, but only when the services they provide are actually needed. - -In this overview you will learn how to write your own service providers and register them with your Laravel application. - - -## Writing Service Providers - -All service providers extend the `Illuminate\Support\ServiceProvider` class. Most service providers contain a `register` and a `boot` method. Within the `register` method, you should **only bind things into the [service container](/docs/{{version}}/container)**. You should never attempt to register any event listeners, routes, or any other piece of functionality within the `register` method. - -The Artisan CLI can generate a new provider via the `make:provider` command: - - php artisan make:provider RiakServiceProvider - - -### The Register Method - -As mentioned previously, within the `register` method, you should only bind things into the [service container](/docs/{{version}}/container). You should never attempt to register any event listeners, routes, or any other piece of functionality within the `register` method. Otherwise, you may accidently use a service that is provided by a service provider which has not loaded yet. - -Let's take a look at a basic service provider. Within any of your service provider methods, you always have access to the `$app` property which provides access to the service container: - - app->singleton(Connection::class, function ($app) { - return new Connection(config('riak')); - }); - } - } - -This service provider only defines a `register` method, and uses that method to define an implementation of `Riak\Connection` in the service container. If you don't understand how the service container works, check out [its documentation](/docs/{{version}}/container). - - -### The Boot Method - -So, what if we need to register a view composer within our service provider? This should be done within the `boot` method. **This method is called after all other service providers have been registered**, meaning you have access to all other services that have been registered by the framework: - - composer('view', function () { - // - }); - } - } - -#### Boot Method Dependency Injection - -You may type-hint dependencies for your service provider's `boot` method. The [service container](/docs/{{version}}/container) will automatically inject any dependencies you need: - - use Illuminate\Contracts\Routing\ResponseFactory; - - public function boot(ResponseFactory $response) - { - $response->macro('caps', function ($value) { - // - }); - } - - -## Registering Providers - -All service providers are registered in the `config/app.php` configuration file. This file contains a `providers` array where you can list the class names of your service providers. By default, a set of Laravel core service providers are listed in this array. These providers bootstrap the core Laravel components, such as the mailer, queue, cache, and others. - -To register your provider, simply add it to the array: - - 'providers' => [ - // Other Service Providers - - App\Providers\ComposerServiceProvider::class, - ], - - -## Deferred Providers - -If your provider is **only** registering bindings in the [service container](/docs/{{version}}/container), you may choose to defer its registration until one of the registered bindings is actually needed. Deferring the loading of such a provider will improve the performance of your application, since it is not loaded from the filesystem on every request. - -Laravel compiles and stores a list of all of the services supplied by deferred service providers, along with the name of its service provider class. Then, only when you attempt to resolve one of these services does Laravel load the service provider. - -To defer the loading of a provider, set the `defer` property to `true` and define a `provides` method. The `provides` method should return the service container bindings registered by the provider: - - app->singleton(Connection::class, function ($app) { - return new Connection($app['config']['riak']); - }); - } - - /** - * Get the services provided by the provider. - * - * @return array - */ - public function provides() - { - return [Connection::class]; - } - - } diff --git a/queries.md b/queries.md old mode 100644 new mode 100755 index 27c5e8a..3d1cb11 --- a/queries.md +++ b/queries.md @@ -1,554 +1,318 @@ -# Database: Query Builder +# Query Builder - [Introduction](#introduction) -- [Retrieving Results](#retrieving-results) - - [Chunking Results](#chunking-results) - - [Aggregates](#aggregates) - [Selects](#selects) -- [Raw Expressions](#raw-expressions) - [Joins](#joins) -- [Unions](#unions) -- [Where Clauses](#where-clauses) - - [Parameter Grouping](#parameter-grouping) - - [Where Exists Clauses](#where-exists-clauses) - - [JSON Where Clauses](#json-where-clauses) -- [Ordering, Grouping, Limit, & Offset](#ordering-grouping-limit-and-offset) -- [Conditional Clauses](#conditional-clauses) +- [Advanced Wheres](#advanced-wheres) +- [Aggregates](#aggregates) +- [Raw Expressions](#raw-expressions) - [Inserts](#inserts) - [Updates](#updates) - - [Updating JSON Columns](#updating-json-columns) - - [Increment & Decrement](#increment-and-decrement) - [Deletes](#deletes) +- [Unions](#unions) - [Pessimistic Locking](#pessimistic-locking) +- [Caching Queries](#caching-queries) ## Introduction -Laravel's database query builder provides a convenient, fluent interface to creating and running database queries. It can be used to perform most database operations in your application and works on all supported database systems. +The database query builder provides a convenient, fluent interface to creating and running database queries. It can be used to perform most database operations in your application, and works on all supported database systems. -The Laravel query builder uses PDO parameter binding to protect your application against SQL injection attacks. There is no need to clean strings being passed as bindings. +> **Note:** The Laravel query builder uses PDO parameter binding throughout to protect your application against SQL injection attacks. There is no need to clean strings being passed as bindings. - -## Retrieving Results + +## Selects #### Retrieving All Rows From A Table -You may use the `table` method on the `DB` facade to begin a query. The `table` method returns a fluent query builder instance for the given table, allowing you to chain more constraints onto the query and then finally get the results using the `get` method: - - get(); - namespace App\Http\Controllers; + foreach ($users as $user) + { + var_dump($user->name); + } - use Illuminate\Support\Facades\DB; - use App\Http\Controllers\Controller; +#### Retrieving A Single Row From A Table - class UserController extends Controller - { - /** - * Show a list of all of the application's users. - * - * @return Response - */ - public function index() - { - $users = DB::table('users')->get(); + $user = DB::table('users')->where('name', 'John')->first(); - return view('user.index', ['users' => $users]); - } - } + var_dump($user->name); -The `get` method returns an `Illuminate\Support\Collection` containing the results where each result is an instance of the PHP `StdClass` object. You may access each column's value by accessing the column as a property of the object: +#### Retrieving A Single Column From A Row - foreach ($users as $user) { - echo $user->name; - } - -#### Retrieving A Single Row / Column From A Table - -If you just need to retrieve a single row from the database table, you may use the `first` method. This method will return a single `StdClass` object: - - $user = DB::table('users')->where('name', 'John')->first(); - - echo $user->name; - -If you don't even need an entire row, you may extract a single value from a record using the `value` method. This method will return the value of the column directly: - - $email = DB::table('users')->where('name', 'John')->value('email'); + $name = DB::table('users')->where('name', 'John')->pluck('name'); #### Retrieving A List Of Column Values -If you would like to retrieve an array containing the values of a single column, you may use the `pluck` method. In this example, we'll retrieve an array of role titles: - - $titles = DB::table('roles')->pluck('title'); + $roles = DB::table('roles')->lists('title'); - foreach ($titles as $title) { - echo $title; - } +This method will return an array of role titles. You may also specify a custom key column for the returned array: - You may also specify a custom key column for the returned array: + $roles = DB::table('roles')->lists('title', 'name'); - $roles = DB::table('roles')->pluck('title', 'name'); - - foreach ($roles as $name => $title) { - echo $title; - } - - -### Chunking Results +#### Specifying A Select Clause -If you need to work with thousands of database records, consider using the `chunk` method. This method retrieves a small chunk of the results at a time and feeds each chunk into a `Closure` for processing. This method is very useful for writing [Artisan commands](/docs/{{version}}/artisan) that process thousands of records. For example, let's work with the entire `users` table in chunks of 100 records at a time: + $users = DB::table('users')->select('name', 'email')->get(); - DB::table('users')->orderBy('id')->chunk(100, function($users) { - foreach ($users as $user) { - // - } - }); + $users = DB::table('users')->distinct()->get(); -You may stop further chunks from being processed by returning `false` from the `Closure`: + $users = DB::table('users')->select('name as user_name')->get(); - DB::table('users')->orderBy('id')->chunk(100, function($users) { - // Process the records... +#### Adding A Select Clause To An Existing Query - return false; - }); + $query = DB::table('users')->select('name'); - -### Aggregates + $users = $query->addSelect('age')->get(); -The query builder also provides a variety of aggregate methods such as `count`, `max`, `min`, `avg`, and `sum`. You may call any of these methods after constructing your query: +#### Using Where Operators - $users = DB::table('users')->count(); + $users = DB::table('users')->where('votes', '>', 100)->get(); - $price = DB::table('orders')->max('price'); +#### Or Statements -Of course, you may combine these methods with other clauses: + $users = DB::table('users') + ->where('votes', '>', 100) + ->orWhere('name', 'John') + ->get(); - $price = DB::table('orders') - ->where('finalized', 1) - ->avg('price'); +#### Using Where Between - -## Selects + $users = DB::table('users') + ->whereBetween('votes', array(1, 100))->get(); -#### Specifying A Select Clause +#### Using Where Not Between -Of course, you may not always want to select all columns from a database table. Using the `select` method, you can specify a custom `select` clause for the query: + $users = DB::table('users') + ->whereNotBetween('votes', array(1, 100))->get(); - $users = DB::table('users')->select('name', 'email as user_email')->get(); +#### Using Where In With An Array -The `distinct` method allows you to force the query to return distinct results: + $users = DB::table('users') + ->whereIn('id', array(1, 2, 3))->get(); - $users = DB::table('users')->distinct()->get(); + $users = DB::table('users') + ->whereNotIn('id', array(1, 2, 3))->get(); -If you already have a query builder instance and you wish to add a column to its existing select clause, you may use the `addSelect` method: +#### Using Where Null To Find Records With Unset Values - $query = DB::table('users')->select('name'); + $users = DB::table('users') + ->whereNull('updated_at')->get(); - $users = $query->addSelect('age')->get(); +#### Order By, Group By, And Having - -## Raw Expressions + $users = DB::table('users') + ->orderBy('name', 'desc') + ->groupBy('count') + ->having('count', '>', 100) + ->get(); -Sometimes you may need to use a raw expression in a query. These expressions will be injected into the query as strings, so be careful not to create any SQL injection points! To create a raw expression, you may use the `DB::raw` method: +#### Offset & Limit - $users = DB::table('users') - ->select(DB::raw('count(*) as user_count, status')) - ->where('status', '<>', 1) - ->groupBy('status') - ->get(); + $users = DB::table('users')->skip(10)->take(5)->get(); ## Joins -#### Inner Join Clause - -The query builder may also be used to write join statements. To perform a basic "inner join", you may use the `join` method on a query builder instance. The first argument passed to the `join` method is the name of the table you need to join to, while the remaining arguments specify the column constraints for the join. Of course, as you can see, you can join to multiple tables in a single query: - - $users = DB::table('users') - ->join('contacts', 'users.id', '=', 'contacts.user_id') - ->join('orders', 'users.id', '=', 'orders.user_id') - ->select('users.*', 'contacts.phone', 'orders.price') - ->get(); - -#### Left Join Clause +The query builder may also be used to write join statements. Take a look at the following examples: -If you would like to perform a "left join" instead of an "inner join", use the `leftJoin` method. The `leftJoin` method has the same signature as the `join` method: +#### Basic Join Statement - $users = DB::table('users') - ->leftJoin('posts', 'users.id', '=', 'posts.user_id') - ->get(); + DB::table('users') + ->join('contacts', 'users.id', '=', 'contacts.user_id') + ->join('orders', 'users.id', '=', 'orders.user_id') + ->select('users.id', 'contacts.phone', 'orders.price') + ->get(); -#### Cross Join Clause +#### Left Join Statement -To perform a "cross join" use the `crossJoin` method with the name of the table you wish to cross join to. Cross joins generate a cartesian product between the first table and the joined table: + DB::table('users') + ->leftJoin('posts', 'users.id', '=', 'posts.user_id') + ->get(); - $users = DB::table('sizes') - ->crossJoin('colours') - ->get(); +You may also specify more advanced join clauses: -#### Advanced Join Clauses - -You may also specify more advanced join clauses. To get started, pass a `Closure` as the second argument into the `join` method. The `Closure` will receive a `JoinClause` object which allows you to specify constraints on the `join` clause: - - DB::table('users') - ->join('contacts', function ($join) { - $join->on('users.id', '=', 'contacts.user_id')->orOn(...); - }) - ->get(); + DB::table('users') + ->join('contacts', function($join) + { + $join->on('users.id', '=', 'contacts.user_id')->orOn(...); + }) + ->get(); If you would like to use a "where" style clause on your joins, you may use the `where` and `orWhere` methods on a join. Instead of comparing two columns, these methods will compare the column against a value: - DB::table('users') - ->join('contacts', function ($join) { - $join->on('users.id', '=', 'contacts.user_id') - ->where('contacts.user_id', '>', 5); - }) - ->get(); - - -## Unions - -The query builder also provides a quick way to "union" two queries together. For example, you may create an initial query and use the `union` method to union it with a second query: - - $first = DB::table('users') - ->whereNull('first_name'); - - $users = DB::table('users') - ->whereNull('last_name') - ->union($first) - ->get(); - -> {tip} The `unionAll` method is also available and has the same method signature as `union`. - - -## Where Clauses - -#### Simple Where Clauses - -You may use the `where` method on a query builder instance to add `where` clauses to the query. The most basic call to `where` requires three arguments. The first argument is the name of the column. The second argument is an operator, which can be any of the database's supported operators. Finally, the third argument is the value to evaluate against the column. - -For example, here is a query that verifies the value of the "votes" column is equal to 100: - - $users = DB::table('users')->where('votes', '=', 100)->get(); - -For convenience, if you simply want to verify that a column is equal to a given value, you may pass the value directly as the second argument to the `where` method: - - $users = DB::table('users')->where('votes', 100)->get(); - -Of course, you may use a variety of other operators when writing a `where` clause: - - $users = DB::table('users') - ->where('votes', '>=', 100) - ->get(); - - $users = DB::table('users') - ->where('votes', '<>', 100) - ->get(); - - $users = DB::table('users') - ->where('name', 'like', 'T%') - ->get(); - -You may also pass an array of conditions to the `where` function: - - $users = DB::table('users')->where([ - ['status', '=', '1'], - ['subscribed', '<>', '1'], - ])->get(); - -#### Or Statements - -You may chain where constraints together as well as add `or` clauses to the query. The `orWhere` method accepts the same arguments as the `where` method: - - $users = DB::table('users') - ->where('votes', '>', 100) - ->orWhere('name', 'John') - ->get(); - -#### Additional Where Clauses + DB::table('users') + ->join('contacts', function($join) + { + $join->on('users.id', '=', 'contacts.user_id') + ->where('contacts.user_id', '>', 5); + }) + ->get(); -**whereBetween** + +## Advanced Wheres -The `whereBetween` method verifies that a column's value is between two values: +#### Parameter Grouping - $users = DB::table('users') - ->whereBetween('votes', [1, 100])->get(); +Sometimes you may need to create more advanced where clauses such as "where exists" or nested parameter groupings. The Laravel query builder can handle these as well: -**whereNotBetween** - -The `whereNotBetween` method verifies that a column's value lies outside of two values: - - $users = DB::table('users') - ->whereNotBetween('votes', [1, 100]) - ->get(); - -**whereIn / whereNotIn** - -The `whereIn` method verifies that a given column's value is contained within the given array: - - $users = DB::table('users') - ->whereIn('id', [1, 2, 3]) - ->get(); - -The `whereNotIn` method verifies that the given column's value is **not** contained in the given array: - - $users = DB::table('users') - ->whereNotIn('id', [1, 2, 3]) - ->get(); - -**whereNull / whereNotNull** - -The `whereNull` method verifies that the value of the given column is `NULL`: - - $users = DB::table('users') - ->whereNull('updated_at') - ->get(); - -The `whereNotNull` method verifies that the column's value is not `NULL`: - - $users = DB::table('users') - ->whereNotNull('updated_at') - ->get(); - -**whereDate / whereMonth / whereDay / whereYear** - -The `whereDate` method may be used compare a column's value against a date: - - $users = DB::table('users') - ->whereDate('created_at', '2016-10-10') - ->get(); - -The `whereMonth` method may be used compare a column's value against a specific month of an year: - - $users = DB::table('users') - ->whereMonth('created_at', '10') - ->get(); - -The `whereDay` method may be used compare a column's value against a specific day of a month: - - $users = DB::table('users') - ->whereDay('created_at', '10') - ->get(); - -The `whereYear` method may be used compare a column's value against a specific year: - - $users = DB::table('users') - ->whereYear('created_at', '2016') - ->get(); - -**whereColumn** - -The `whereColumn` method may be used to verify that two columns are equal: - - $users = DB::table('users') - ->whereColumn('first_name', 'last_name') - ->get(); - -You may also pass a comparison operator to the method: - - $users = DB::table('users') - ->whereColumn('updated_at', '>', 'created_at') - ->get(); - -The `whereColumn` method can also be passed an array of multiple conditions. These conditions will be joined using the `and` operator: - - $users = DB::table('users') - ->whereColumn([ - ['first_name', '=', 'last_name'], - ['updated_at', '>', 'created_at'] - ])->get(); - - -### Parameter Grouping - -Sometimes you may need to create more advanced where clauses such as "where exists" clauses or nested parameter groupings. The Laravel query builder can handle these as well. To get started, let's look at an example of grouping constraints within parenthesis: - - DB::table('users') - ->where('name', '=', 'John') - ->orWhere(function ($query) { - $query->where('votes', '>', 100) - ->where('title', '<>', 'Admin'); - }) - ->get(); - -As you can see, passing a `Closure` into the `orWhere` method instructs the query builder to begin a constraint group. The `Closure` will receive a query builder instance which you can use to set the constraints that should be contained within the parenthesis group. The example above will produce the following SQL: - - select * from users where name = 'John' or (votes > 100 and title <> 'Admin') - - -### Where Exists Clauses - -The `whereExists` method allows you to write `where exists` SQL clauses. The `whereExists` method accepts a `Closure` argument, which will receive a query builder instance allowing you to define the query that should be placed inside of the "exists" clause: - - DB::table('users') - ->whereExists(function ($query) { - $query->select(DB::raw(1)) - ->from('orders') - ->whereRaw('orders.user_id = users.id'); - }) - ->get(); + DB::table('users') + ->where('name', '=', 'John') + ->orWhere(function($query) + { + $query->where('votes', '>', 100) + ->where('title', '<>', 'Admin'); + }) + ->get(); The query above will produce the following SQL: - select * from users - where exists ( - select 1 from orders where orders.user_id = users.id - ) - - -### JSON Where Clauses - -Laravel also supports querying JSON column types on databases that provide support for JSON column types. Currently, this includes MySQL 5.7 and Postgres. To query a JSON column, use the `->` operator: + select * from users where name = 'John' or (votes > 100 and title <> 'Admin') - $users = DB::table('users') - ->where('options->language', 'en') - ->get(); +#### Exists Statements - $users = DB::table('users') - ->where('preferences->dining->meal', 'salad') - ->get(); + DB::table('users') + ->whereExists(function($query) + { + $query->select(DB::raw(1)) + ->from('orders') + ->whereRaw('orders.user_id = users.id'); + }) + ->get(); - -## Ordering, Grouping, Limit, & Offset +The query above will produce the following SQL: -#### orderBy + select * from users + where exists ( + select 1 from orders where orders.user_id = users.id + ) -The `orderBy` method allows you to sort the result of the query by a given column. The first argument to the `orderBy` method should be the column you wish to sort by, while the second argument controls the direction of the sort and may be either `asc` or `desc`: + +## Aggregates - $users = DB::table('users') - ->orderBy('name', 'desc') - ->get(); +The query builder also provides a variety of aggregate methods, such as `count`, `max`, `min`, `avg`, and `sum`. -#### inRandomOrder +#### Using Aggregate Methods -The `inRandomOrder` method may be used to sort the query results randomly. For example, you may use this method to fetch a random user: + $users = DB::table('users')->count(); - $randomUser = DB::table('users') - ->inRandomOrder() - ->first(); + $price = DB::table('orders')->max('price'); -#### groupBy / having / havingRaw + $price = DB::table('orders')->min('price'); -The `groupBy` and `having` methods may be used to group the query results. The `having` method's signature is similar to that of the `where` method: + $price = DB::table('orders')->avg('price'); - $users = DB::table('users') - ->groupBy('account_id') - ->having('account_id', '>', 100) - ->get(); + $total = DB::table('users')->sum('votes'); -The `havingRaw` method may be used to set a raw string as the value of the `having` clause. For example, we can find all of the departments with sales greater than $2,500: + +## Raw Expressions - $users = DB::table('orders') - ->select('department', DB::raw('SUM(price) as total_sales')) - ->groupBy('department') - ->havingRaw('SUM(price) > 2500') - ->get(); +Sometimes you may need to use a raw expression in a query. These expressions will be injected into the query as strings, so be careful not to create any SQL injection points! To create a raw expression, you may use the `DB::raw` method: -#### skip / take +#### Using A Raw Expression -To limit the number of results returned from the query, or to skip a given number of results in the query, you may use the `skip` and `take` methods: + $users = DB::table('users') + ->select(DB::raw('count(*) as user_count, status')) + ->where('status', '<>', 1) + ->groupBy('status') + ->get(); - $users = DB::table('users')->skip(10)->take(5)->get(); +#### Incrementing or decrementing a value of a column - -## Conditional Clauses + DB::table('users')->increment('votes'); -Sometimes you may want clauses to apply to a query only when something else is true. For instance you may only want to apply a `where` statement if a given input value is present on the incoming request. You may accomplish this using the `when` method: + DB::table('users')->increment('votes', 5); - $role = $request->input('role'); + DB::table('users')->decrement('votes'); - $users = DB::table('users') - ->when($role, function ($query) use ($role) { - return $query->where('role_id', $role); - }) - ->get(); + DB::table('users')->decrement('votes', 5); +You may also specify additional columns to update: -The `when` method only executes the given Closure when the first parameter is `true`. If the first parameter is `false`, the Closure will not be executed. + DB::table('users')->increment('votes', 1, array('name' => 'John')); ## Inserts -The query builder also provides an `insert` method for inserting records into the database table. The `insert` method accepts an array of column names and values: +#### Inserting Records Into A Table - DB::table('users')->insert( - ['email' => 'john@example.com', 'votes' => 0] - ); + DB::table('users')->insert( + array('email' => 'john@example.com', 'votes' => 0) + ); -You may even insert several records into the table with a single call to `insert` by passing an array of arrays. Each array represents a row to be inserted into the table: +#### Inserting Records Into A Table With An Auto-Incrementing ID - DB::table('users')->insert([ - ['email' => 'taylor@example.com', 'votes' => 0], - ['email' => 'dayle@example.com', 'votes' => 0] - ]); +If the table has an auto-incrementing id, use `insertGetId` to insert a record and retrieve the id: -#### Auto-Incrementing IDs + $id = DB::table('users')->insertGetId( + array('email' => 'john@example.com', 'votes' => 0) + ); -If the table has an auto-incrementing id, use the `insertGetId` method to insert a record and then retrieve the ID: +> **Note:** When using PostgreSQL the insertGetId method expects the auto-incrementing column to be named "id". - $id = DB::table('users')->insertGetId( - ['email' => 'john@example.com', 'votes' => 0] - ); +#### Inserting Multiple Records Into A Table -> {note} When using PostgreSQL the insertGetId method expects the auto-incrementing column to be named `id`. If you would like to retrieve the ID from a different "sequence", you may pass the sequence name as the second parameter to the `insertGetId` method. + DB::table('users')->insert(array( + array('email' => 'taylor@example.com', 'votes' => 0), + array('email' => 'dayle@example.com', 'votes' => 0), + )); ## Updates -Of course, in addition to inserting records into the database, the query builder can also update existing records using the `update` method. The `update` method, like the `insert` method, accepts an array of column and value pairs containing the columns to be updated. You may constrain the `update` query using `where` clauses: +#### Updating Records In A Table - DB::table('users') - ->where('id', 1) - ->update(['votes' => 1]); + DB::table('users') + ->where('id', 1) + ->update(array('votes' => 1)); - -### Updating JSON Columns + +## Deletes -When updating a JSON column, you should use `->` syntax to access the appropriate key in the JSON object. This operation is only supported on databases that support JSON columns: +#### Deleting Records In A Table - DB::table('users') - ->where('id', 1) - ->update(['options->enabled' => true]); + DB::table('users')->where('votes', '<', 100)->delete(); - -### Increment & Decrement +#### Deleting All Records From A Table -The query builder also provides convenient methods for incrementing or decrementing the value of a given column. This is simply a short-cut, providing a more expressive and terse interface compared to manually writing the `update` statement. + DB::table('users')->delete(); -Both of these methods accept at least one argument: the column to modify. A second argument may optionally be passed to control the amount by which the column should be incremented or decremented: +#### Truncating A Table - DB::table('users')->increment('votes'); + DB::table('users')->truncate(); - DB::table('users')->increment('votes', 5); + +## Unions - DB::table('users')->decrement('votes'); +The query builder also provides a quick way to "union" two queries together: - DB::table('users')->decrement('votes', 5); + $first = DB::table('users')->whereNull('first_name'); -You may also specify additional columns to update during the operation: + $users = DB::table('users')->whereNull('last_name')->union($first)->get(); - DB::table('users')->increment('votes', 1, ['name' => 'John']); +The `unionAll` method is also available, and has the same method signature as `union`. - -## Deletes + +## Pessimistic Locking -The query builder may also be used to delete records from the table via the `delete` method. You may constrain `delete` statements by adding `where` clauses before calling the `delete` method: +The query builder includes a few functions to help you do "pessimistic locking" on your SELECT statements. - DB::table('users')->delete(); +To run the SELECT statement with a "shared lock", you may use the `sharedLock` method on a query: - DB::table('users')->where('votes', '>', 100)->delete(); + DB::table('users')->where('votes', '>', 100)->sharedLock()->get(); -If you wish to truncate the entire table, which will remove all rows and reset the auto-incrementing ID to zero, you may use the `truncate` method: +To "lock for update" on a SELECT statement, you may use the `lockForUpdate` method on a query: - DB::table('users')->truncate(); + DB::table('users')->where('votes', '>', 100)->lockForUpdate()->get(); - -## Pessimistic Locking + +## Caching Queries + +You may easily cache the results of a query using the `remember` method: -The query builder also includes a few functions to help you do "pessimistic locking" on your `select` statements. To run the statement with a "shared lock", you may use the `sharedLock` method on a query. A shared lock prevents the selected rows from being modified until your transaction commits: + $users = DB::table('users')->remember(10)->get(); - DB::table('users')->where('votes', '>', 100)->sharedLock()->get(); +In this example, the results of the query will be cached for ten minutes. While the results are cached, the query will not be run against the database, and the results will be loaded from the default cache driver specified for your application. -Alternatively, you may use the `lockForUpdate` method. A "for update" lock prevents the rows from being modified or from being selected with another shared lock: +If you are using a [supported cache driver](cache#cache-tags.md), you can also add tags to the caches: - DB::table('users')->where('votes', '>', 100)->lockForUpdate()->get(); + $users = DB::table('users')->cacheTags(array('people', 'authors'))->remember(10)->get(); diff --git a/queues.md b/queues.md old mode 100644 new mode 100755 index 6b95928..fd7234e --- a/queues.md +++ b/queues.md @@ -1,549 +1,255 @@ # Queues -- [Introduction](#introduction) - - [Connections Vs. Queues](#connections-vs-queues) - - [Driver Prerequisites](#driver-prerequisites) -- [Creating Jobs](#creating-jobs) - - [Generating Job Classes](#generating-job-classes) - - [Class Structure](#class-structure) -- [Dispatching Jobs](#dispatching-jobs) - - [Delayed Dispatching](#delayed-dispatching) - - [Customizing The Queue & Connection](#customizing-the-queue-and-connection) - - [Error Handling](#error-handling) -- [Running The Queue Worker](#running-the-queue-worker) - - [Queue Priorities](#queue-priorities) - - [Queue Workers & Deployment](#queue-workers-and-deployment) - - [Job Expirations & Timeouts](#job-expirations-and-timeouts) -- [Supervisor Configuration](#supervisor-configuration) -- [Dealing With Failed Jobs](#dealing-with-failed-jobs) - - [Cleaning Up After Failed Jobs](#cleaning-up-after-failed-jobs) - - [Failed Job Events](#failed-job-events) - - [Retrying Failed Jobs](#retrying-failed-jobs) -- [Job Events](#job-events) +- [Configuration](#configuration) +- [Basic Usage](#basic-usage) +- [Queueing Closures](#queueing-closures) +- [Running The Queue Listener](#running-the-queue-listener) +- [Daemon Queue Worker](#daemon-queue-worker) +- [Push Queues](#push-queues) +- [Failed Jobs](#failed-jobs) - -## Introduction + +## Configuration -Laravel queues provide a unified API across a variety of different queue backends, such as Beanstalk, Amazon SQS, Redis, or even a relational database. Queues allow you to defer the processing of a time consuming task, such as sending an email, until a later time. Deferring these time consuming tasks drastically speeds up web requests to your application. +The Laravel Queue component provides a unified API across a variety of different queue services. Queues allow you to defer the processing of a time consuming task, such as sending an e-mail, until a later time, thus drastically speeding up the web requests to your application. -The queue configuration file is stored in `config/queue.php`. In this file you will find connection configurations for each of the queue drivers that are included with the framework, which includes a database, [Beanstalkd](http://kr.github.com/beanstalkd), [Amazon SQS](http://aws.amazon.com/sqs), [Redis](http://redis.io), and synchronous (for local use) driver. A `null` queue driver is also included which simply discards queued jobs. - - -### Connections Vs. Queues - -Before getting started with Laravel queues, it is important to understand the distinction between "connections" and "queues". In your `config/queue.php` configuration file, there is a `connections` configuration option. This option defines a particular connection to a backend service such as Amazon SQS, Beanstalk, or Redis. However, any given queue connection may have multiple "queues" which may be thought of as different stacks or piles of queued jobs. - -Note that each connection configuration example in the `queue` configuration file contains a `queue` attribute. This is the default queue that jobs will be dispatched to when they are sent to a given connection. In other words, if you dispatch a job without explicitly defining which queue it should be dispatched to, the job will be placed on the queue that is defined in the `queue` attribute of the connection configuration: - - // This job is sent to the default queue... - dispatch(new Job); - - // This job is sent to the "emails" queue... - dispatch((new Job)->onQueue('emails')); - -Some applications may not need to ever push jobs onto multiples queues, instead preferring to have one simple queue. However, pushing jobs to multiple queues can be especially useful for applications that wish to prioritize or segment how jobs are processed, since the Laravel queue worker allows you to specify which queues it should process by priority. For example, if you push jobs to a `high` queue, you may run a worker that gives them higher processing priority: - - php artisan queue:work --queue=high,default - - -### Driver Prerequisites - -#### Database - -In order to use the `database` queue driver, you will need a database table to hold the jobs. To generate a migration that creates this table, run the `queue:table` Artisan command. Once the migration has been created, you may migrate your database using the `migrate` command: - - php artisan queue:table - - php artisan migrate - -#### Other Driver Prerequisites +The queue configuration file is stored in `app/config/queue.php`. In this file you will find connection configurations for each of the queue drivers that are included with the framework, which includes a [Beanstalkd](http://kr.github.com/beanstalkd), [IronMQ](http://iron.io), [Amazon SQS](http://aws.amazon.com/sqs), [Redis](http://redis.io), and synchronous (for local use) driver. The following dependencies are needed for the listed queue drivers: -
    -- Amazon SQS: `aws/aws-sdk-php ~3.0` -- Beanstalkd: `pda/pheanstalk ~3.0` -- Redis: `predis/predis ~1.0` -
    - - -## Creating Jobs - - -### Generating Job Classes - -By default, all of the queueable jobs for your application are stored in the `app/Jobs` directory. If the `app/Jobs` directory doesn't exist, it will be created when you run the `make:job` Artisan command. You may generate a new queued job using the Artisan CLI: - - php artisan make:job SendReminderEmail - -The generated class will implement the `Illuminate\Contracts\Queue\ShouldQueue` interface, indicating to Laravel that the job should be pushed onto the queue instead of run synchronously. - - -### Class Structure - -Job classes are very simple, normally containing only a `handle` method which is called when the job is processed by the queue. To get started, let's take a look at an example job class. In this example, we'll pretend we manage a podcast publishing service and need to process the uploaded podcast files before they are published: - - podcast = $podcast; - } - - /** - * Execute the job. - * - * @param AudioProcessor $processor - * @return void - */ - public function handle(AudioProcessor $processor) - { - // Process uploaded podcast... - } - } - -In this example, note that we were able to pass an [Eloquent model](/docs/{{version}}/eloquent) directly into the queued job's constructor. Because of the `SerializesModels` trait that the job is using, Eloquent models will be gracefully serialized and unserialized when the job is processing. If your queued job accepts an Eloquent model in its constructor, only the identifier for the model will be serialized onto the queue. When the job is actually handled, the queue system will automatically re-retrieve the full model instance from the database. It's all totally transparent to your application and prevents issues that can arise from serializing full Eloquent model instances. - -The `handle` method is called when the job is processed by the queue. Note that we are able to type-hint dependencies on the `handle` method of the job. The Laravel [service container](/docs/{{version}}/container) automatically injects these dependencies. - - -## Dispatching Jobs - -Once you have written your job class, you may dispatch it using the `dispatch` helper. The only argument you need to pass to the `dispatch` helper is an instance of the job: - - {tip} The `dispatch` helper provides the convenience of a short, globally available function, while also being extremely easy to test. Check out the Laravel [testing documentation](/docs/{{version}}/testing) to learn more. + +## Basic Usage - -### Delayed Dispatching +#### Pushing A Job Onto The Queue -If you would like to delay the execution of a queued job, you may use the `delay` method on your job instance. The `delay` method is provided by the `Illuminate\Bus\Queueable` trait, which is included by default on all generated job classes. For example, let's specify that a job should not be available for processing until 10 minutes after it has been dispatched: +To push a new job onto the queue, use the `Queue::push` method: - $message)); - namespace App\Http\Controllers; +#### Defining A Job Handler - use Carbon\Carbon; - use App\Jobs\ProcessPodcast; - use Illuminate\Http\Request; - use App\Http\Controllers\Controller; +The first argument given to the `push` method is the name of the class that should be used to process the job. The second argument is an array of data that should be passed to the handler. A job handler should be defined like so: - class PodcastController extends Controller - { - /** - * Store a new podcast. - * - * @param Request $request - * @return Response - */ - public function store(Request $request) - { - // Create podcast... + class SendEmail { - $job = (new ProcessPodcast($pocast)) - ->delay(Carbon::now()->addMinutes(10)); + public function fire($job, $data) + { + // + } - dispatch($job); - } - } + } -> {note} The Amazon SQS queue service has a maximum delay time of 15 minutes. +Notice the only method that is required is `fire`, which receives a `Job` instance as well as the array of `data` that was pushed onto the queue. - -### Customizing The Queue & Connection +#### Specifying A Custom Handler Method -#### Dispatching To A Particular Queue +If you want the job to use a method other than `fire`, you may specify the method when you push the job: -By pushing jobs to different queues, you may "categorize" your queued jobs and even prioritize how many workers you assign to various queues. Keep in mind, this does not push jobs to different queue "connections" as defined by your queue configuration file, but only to specific queues within a single connection. To specify the queue, use the `onQueue` method on the job instance: + Queue::push('SendEmail@send', array('message' => $message)); - $message), 'emails'); - class PodcastController extends Controller - { - /** - * Store a new podcast. - * - * @param Request $request - * @return Response - */ - public function store(Request $request) - { - // Create podcast... +#### Passing The Same Payload To Multiple Jobs - $job = (new ProcessPodcast($podcast))->onQueue('processing'); +If you need to pass the same data to several queue jobs, you may use the `Queue::bulk` method: - dispatch($job); - } - } + Queue::bulk(array('SendEmail', 'NotifyUser'), $payload); -#### Dispatching To A Particular Connection +#### Delaying The Execution Of A Job -If you are working with multiple queue connections, you may specify which connection to push a job to. To specify the connection, use the `onConnection` method on the job instance: +Sometimes you may wish to delay the execution of a queued job. For instance, you may wish to queue a job that sends a customer an e-mail 15 minutes after sign-up. You can accomplish this using the `Queue::later` method: - addMinutes(15); - namespace App\Http\Controllers; + Queue::later($date, 'SendEmail@send', array('message' => $message)); - use App\Jobs\ProcessPodcast; - use Illuminate\Http\Request; - use App\Http\Controllers\Controller; +In this example, we're using the [Carbon](https://github.com/briannesbitt/Carbon) date library to specify the delay we wish to assign to the job. Alternatively, you may pass the number of seconds you wish to delay as an integer. - class PodcastController extends Controller - { - /** - * Store a new podcast. - * - * @param Request $request - * @return Response - */ - public function store(Request $request) - { - // Create podcast... +#### Deleting A Processed Job - $job = (new ProcessPodcast($podcast))->onConnection('sqs'); +Once you have processed a job, it must be deleted from the queue, which can be done via the `delete` method on the `Job` instance: - dispatch($job); - } - } + public function fire($job, $data) + { + // Process the job... -Of course, you may chain the `onConnection` and `onQueue` methods to specify the connection and the queue for a job: + $job->delete(); + } - $job = (new ProcessPodcast($podcast)) - ->onConnection('sqs') - ->onQueue('processing'); +#### Releasing A Job Back Onto The Queue - -### Error Handling +If you wish to release a job back onto the queue, you may do so via the `release` method: -If an exception is thrown while the job is being processed, the job will automatically be released back onto the queue so it may be attempted again. The job will continue to be released until it has been attempted the maximum number of times allowed by your application. The number of maximum attempts is defined by the `--tries` switch used on the `queue:work` Artisan command. More information on running the queue worker [can be found below](#running-the-queue-worker). + public function fire($job, $data) + { + // Process the job... - -## Running The Queue Worker + $job->release(); + } -Laravel includes an queue worker that will process new jobs as they are pushed onto the queue. You may run the worker using the `queue:work` Artisan command. Note that once the `queue:work` command has started, it will continue to run until it is manually stopped or you close your terminal: +You may also specify the number of seconds to wait before the job is released: - php artisan queue:work + $job->release(5); -> {tip} To keep the `queue:work` process running permanently in the background, you should use a process monitor such as [Supervisor](#supervisor-configuration) to ensure that the queue worker does not stop running. +#### Checking The Number Of Run Attempts -Remember, queue workers are long lived processes and will not notice changes in your code base after they have been started. So, during your deployment process, be sure to [restart your queue workers](#queue-workers-and-deployment). +If an exception occurs while the job is being processed, it will automatically be released back onto the queue. You may check the number of attempts that have been made to run the job using the `attempts` method: -#### Specifying The Connection & Queue + if ($job->attempts() > 3) + { + // + } -You may also specify which queue connection the worker should utilize. The connection name passed to the `work` command should correspond to one of the connections defined in your `config/queue.php` configuration file: +#### Accessing The Job ID - php artisan queue:work redis +You may also access the job identifier: -You may customize your queue worker even further by only processing particular queues for a given connection. For example, if all of your emails are processed in an `emails` queue on your `redis` queue connection, you may issue the following command to start a worker that only processes only that queue: + $job->getJobId(); - php artisan queue:work redis --queue=emails + +## Queueing Closures -#### Resource Considerations +You may also push a Closure onto the queue. This is very convenient for quick, simple tasks that need to be queued: -Queue workers are daemons and do not restart the framework before processing each job. Therefore, you should be careful to free any heavy resources before your job finishes. For example, if you are doing image manipulation with the GD library, you should free the memory with `imagedestroy` when you are done. +#### Pushing A Closure Onto The Queue - -### Queue Priorities + Queue::push(function($job) use ($id) + { + Account::delete($id); -Sometimes you may wish to prioritize how your queues are processed. For example, in your `config/queue.php` you may set the default `queue` for your `redis` connection to `low`. However, occasionally you may wish to push a job to a `high` priority queue like so: + $job->delete(); + }); - dispatch((new Job)->onQueue('high')); +When using Iron.io [push queues](#push-queues), you should take extra precaution queueing Closures. The end-point that receives your queue messages should check for a token to verify that the request is actually from Iron.io. For example, your push queue end-point should be something like: `https://yourapp.com/queue/receive?token=SecretToken`. You may then check the value of the secret token in your application before marshaling the queue request. -To start a worker that verifies that all of the `high` queue jobs are processed before continuing to any jobs on the `low` queue, pass a comma-delimited list of queue names to the `work` command: + +## Running The Queue Listener - php artisan queue:work --queue=high,low +Laravel includes an Artisan task that will run new jobs as they are pushed onto the queue. You may run this task using the `queue:listen` command: - -### Queue Workers & Deployment +#### Starting The Queue Listener -Since queue workers are long lived processes, they will not pick up changes to your code without being restarted. So, the simplest way to deploy an application using queue workers is to restart the workers during your deployment process. You may gracefully restart all of the workers by issuing the `queue:restart` command: + php artisan queue:listen - php artisan queue:restart +You may also specify which queue connection the listener should utilize: -This command will gracefully instruct all queue workers to "die" after they finish processing their current job so that no existing jobs are lost. Since the queue workers will die when the `queue:restart` command is executed, you should be running a process manager such as [Supervisor](#supervisor-configuration) which automatically restarts the queue workers. + php artisan queue:listen connection - -### Job Expirations & Timeouts +Note that once this task has started, it will continue to run until it is manually stopped. You may use a process monitor such as [Supervisor](http://supervisord.org/) to ensure that the queue listener does not stop running. -#### Job Expiration +You may pass a comma-delimited list of queue connections to the `listen` command to set queue priorities: -In your `config/queue.php` configuration file, each queue connection defines a `retry_after` option. This option specifies how many seconds the queue connection should wait before retrying a job that is being processed. For example, if the value of `retry_after` is set to `90`, the job will be released back onto the queue if it has been processing for 90 seconds without being deleted. Typically, you should set the `retry_after` value to the maximum number of seconds your jobs should reasonably take to complete processing. + php artisan queue:listen --queue=high,low -> {note} The only queue connection which does not contain a `retry_after` value is Amazon SQS. When using SQS, you must configure the retry threshold from the Amazon web console. +In this example, jobs on the `high-connection` will always be processed before moving onto jobs from the `low-connection`. -#### Worker Timeouts +#### Specifying The Job Timeout Parameter -The `queue:work` Artisan command exposes a `--timeout` option. The `--timeout` option specifies how long the Laravel queue master process will wait before killing off a child queue worker that is processing a job. Sometimes a child queue process can become "frozen" for various reasons, such as a external HTTP call that is not responding. The `--timeout` option removes frozen processes that have exceeded that specified time limit: +You may also set the length of time (in seconds) each job should be allowed to run: - php artisan queue:listen --timeout=60 + php artisan queue:listen --timeout=60 -The `retry_after` configuration option and the `--timeout` CLI option are different, but work together to ensure that jobs are not lost and that jobs are only successfully processed once. +#### Specifying Queue Sleep Duration -> {note} The `--timeout` value should always be at least several seconds shorter than your `retry_after` configuration value. This will ensure that a worker processing a given job is always killed before the job is retried. If your `--timeout` option is longer than your `retry_after` configuration value, your jobs may be processed twice. +In addition, you may specify the number of seconds to wait before polling for new jobs: - -## Supervisor Configuration + php artisan queue:listen --sleep=5 -#### Installing Supervisor +Note that the queue only "sleeps" if no jobs are on the queue. If more jobs are available, the queue will continue to work them without sleeping. -Supervisor is a process monitor for the Linux operating system, and will automatically restart your `queue:work` process if it fails. To install Supervisor on Ubuntu, you may use the following command: +#### Processing The First Job On The Queue - sudo apt-get install supervisor +To process only the first job on the queue, you may use the `queue:work` command: -> {tip} If configuring Supervisor yourself sounds overwhelming, consider using [Laravel Forge](https://forge.laravel.com), which will automatically install and configure Supervisor for your Laravel projects. + php artisan queue:work -#### Configuring Supervisor + +## Daemon Queue Workers -Supervisor configuration files are typically stored in the `/etc/supervisor/conf.d` directory. Within this directory, you may create any number of configuration files that instruct supervisor how your processes should be monitored. For example, let's create a `laravel-worker.conf` file that starts and monitors a `queue:work` process: +The `queue:work` also includes a `--daemon` option for forcing the queue worker to continue processing jobs without ever re-booting the framework. This results in a significant reduction of CPU usage when compared to the `queue:listen` command, but at the added complexity of needing to drain the queues of currently executing jobs during your deployments. - [program:laravel-worker] - process_name=%(program_name)s_%(process_num)02d - command=php /home/forge/app.com/artisan queue:work sqs --sleep=3 --tries=3 - autostart=true - autorestart=true - user=forge - numprocs=8 - redirect_stderr=true - stdout_logfile=/home/forge/app.com/worker.log +To start a queue worker in daemon mode, use the `--daemon` flag: -In this example, the `numprocs` directive will instruct Supervisor to run 8 `queue:work` processes and monitor all of them, automatically restarting them if they fail. Of course, you should change the `queue:work sqs` portion of the `command` directive to reflect your desired queue connection. + php artisan queue:work connection --daemon -#### Starting Supervisor + php artisan queue:work connection --daemon --sleep=3 -Once the configuration file has been created, you may update the Supervisor configuration and start the processes using the following commands: + php artisan queue:work connection --daemon --sleep=3 --tries=3 - sudo supervisorctl reread +As you can see, the `queue:work` command supports most of the same options available to `queue:listen`. You may use the `php artisan help queue:work` command to view all of the available options. - sudo supervisorctl update +### Deploying With Daemon Queue Workers - sudo supervisorctl start laravel-worker:* +The simplest way to deploy an application using daemon queue workers is to put the application in maintenance mode at the beginning of your deploymnet. This can be done using the `php artisan down` command. Once the application is in maintenance mode, Laravel will now accept any new jobs off of the queue, but will continue to process existing jobs. Once enough time has passed for all of your existing jobs to execute (usually no longer than 30-60 seconds), you may stop the worker and continue your deployment process. -For more information on Supervisor, consult the [Supervisor documentation](http://supervisord.org/index.html). +If you are using Supervisor or Laravel Forge, which utilizes Supervisor, you may typically stop a worker with a command like the following: - -## Dealing With Failed Jobs + supervisorctl stop worker-1 -Sometimes your queued jobs will fail. Don't worry, things don't always go as planned! Laravel includes a convenient way to specify the maximum number of times a job should be attempted. After a job has exceeded this amount of attempts, it will be inserted into the `failed_jobs` database table. To create a migration for the `failed_jobs` table, you may use the `queue:failed-table` command: +Once the queues have been drained and your fresh code has been deployed to your server, you should restart the daemon queue work. If you are using Supervisor, this can typically be done with a command like this: - php artisan queue:failed-table + supervisorctl start worker-1 - php artisan migrate + +## Push Queues -Then, when running your [queue worker](#running-the-queue-worker), you should specify the maximum number of times a job should be attempted using the `--tries` switch on the `queue:work` command. If you do not specify a value for the `--tries` option, jobs will be attempted indefinitely: +Push queues allow you to utilize the powerful Laravel 4 queue facilities without running any daemons or background listeners. Currently, push queues are only supported by the [Iron.io](http://iron.io) driver. Before getting started, create an Iron.io account, and add your Iron credentials to the `app/config/queue.php` configuration file. - php artisan queue:work redis --tries=3 +#### Registering A Push Queue Subscriber - -### Cleaning Up After Failed Jobs +Next, you may use the `queue:subscribe` Artisan command to register a URL end-point that will receive newly pushed queue jobs: -You may define a `failed` method directly on your job class, allowing you to perform job specific clean-up when a failure occurs. This is the perfect location to send an alert to your users or revert any actions performed by the job. The `Exception` that caused the job to fail will be passed to the `failed` method: + php artisan queue:subscribe queue_name http://foo.com/queue/receive - +## Failed Jobs - protected $podcast; +Since things don't always go as planned, sometimes your queued jobs will fail. Don't worry, it happens to the best of us! Laravel includes a convenient way to specify the maximum number of times a job should be attempted. After a job has exceeded this amount of attempts, it will be inserted into a `failed_jobs` table. The failed jobs table name can be configured via the `app/config/queue.php` configuration file. - /** - * Create a new job instance. - * - * @param Podcast $podcast - * @return void - */ - public function __construct(Podcast $podcast) - { - $this->podcast = $podcast; - } +To create a migration for the `failed_jobs` table, you may use the `queue:failed-table` command: - /** - * Execute the job. - * - * @param AudioProcessor $processor - * @return void - */ - public function handle(AudioProcessor $processor) - { - // Process uploaded podcast... - } + php artisan queue:failed-table - /** - * The job failed to process. - * - * @param Exception $exception - * @return void - */ - public function failed(Exception $e) - { - // Send user notification of failure, etc... - } - } +You can specify the maximum number of times a job should be attempted using the `--tries` switch on the `queue:listen` command: - -### Failed Job Events + php artisan queue:listen connection-name --tries=3 -If you would like to register an event that will be called when a job fails, you may use the `Queue::failing` method. This event is a great opportunity to notify your team via email or [HipChat](https://www.hipchat.com). For example, we may attach a callback to this event from the `AppServiceProvider` that is included with Laravel: +If you would like to register an event that will be called when a queue job fails, you may use the `Queue::failing` method. This event is a great opportunity to notify your team via e-mail or [HipChat](https://www.hipchat.com). - connectionName - // $event->job - // $event->exception - }); - } +The `queue:failed` command will list the job ID, connection, queue, and failure time. The job ID may be used to retry the failed job. For instance, to retry a failed job that has an ID of 5, the following command should be issued: - /** - * Register the service provider. - * - * @return void - */ - public function register() - { - // - } - } - - -### Retrying Failed Jobs - -To view all of your failed jobs that have been inserted into your `failed_jobs` database table, you may use the `queue:failed` Artisan command: - - php artisan queue:failed - -The `queue:failed` command will list the job ID, connection, queue, and failure time. The job ID may be used to retry the failed job. For instance, to retry a failed job that has an ID of `5`, issue the following command: - - php artisan queue:retry 5 - -To retry all of your failed jobs, execute the `queue:retry` command and pass `all` as the ID: - - php artisan queue:retry all + php artisan queue:retry 5 If you would like to delete a failed job, you may use the `queue:forget` command: - php artisan queue:forget 5 + php artisan queue:forget 5 To delete all of your failed jobs, you may use the `queue:flush` command: - php artisan queue:flush - - -## Job Events - -Using the `before` and `after` methods on the `Queue` [facade](/docs/{{version}}/facades), you may specify callbacks to be executed before or after a queued job is processed. These callbacks are a great opportunity to perform additional logging or increment statistics for a dashboard. Typically, you should call these methods from a [service provider](/docs/{{version}}/providers). For example, we may use the `AppServiceProvider` that is included with Laravel: - - connectionName - // $event->job - // $event->job->payload() - }); - - Queue::after(function (JobProcessed $event) { - // $event->connectionName - // $event->job - // $event->job->payload() - }); - } - - /** - * Register the service provider. - * - * @return void - */ - public function register() - { - // - } - } + php artisan queue:flush diff --git a/quick.md b/quick.md new file mode 100755 index 0000000..4a38929 --- /dev/null +++ b/quick.md @@ -0,0 +1,178 @@ +# Laravel Quickstart + +- [Installation](#installation) +- [Routing](#routing) +- [Creating A View](#creating-a-view) +- [Creating A Migration](#creating-a-migration) +- [Eloquent ORM](#eloquent-orm) +- [Displaying Data](#displaying-data) + + +## Installation + +### Laravel Installer ကို အသုံးပြုခြင်း + +ရှေးဦးစွာ [Laravel installer PHAR archive](http://laravel.com/laravel.phar) ကို ဒေါင်းပါ။ အဆင်ပြေစေရန်အတွက် ထို file ကို `laravel` ဟု အမည်ပေးပြီး `/usr/local/bin` ထဲသို ့ပြောင်းရွေ ့လိုက်ပါ။ ထိုနောက် `laravel new` command ဖြင့် သင်ထားရှိထားသော directory ပေါ်တွင် laravel installation အလိုအလျောက် ပြလုပ်သွားမည် ဖြစ်သည်။ ဥပမာ `laravel new blog` ဆိုသည့် command ကိုအသုံးပြပါက `blog` အမည်ရှိ folder တစ်ခုကို တည်ဆောက်ပေးပြီး လိုအပ်သည့် package များကိုပါ တခါတည်း ဒေါင်းလုပ်လုပ်ကာ စုစည်းပေးသွားမည် ဖြစ်သည်။ ၄င်းသို ့ install ပြုလုပ်ခြင်းသည် Composer မှ install လုပ်ခြင်းထက် ပို၍ လျင်မြန်ပါလိမ့်မည်။ + +### Composer ကို အသုံးပြုခြင်း + +Laravel framework ကို [Composer](http://getcomposer.org) မှလည်း installation နှင့် လိုအပ်သည့် package များကို ထည့်သွင်းနိုင်သည်။ Composer မသွင်းရသေးပါက [Composer ထည့်သွင်းခြင်းနည်းလမ်း](http://getcomposer.org/doc/00-intro.md) ကိုကြည့်၍ ထည့်သွင်းနိုင်ပါသည်။ + +ထိုနောက် သင့်အနေဖြင့် terminal မှ အောက်ပါ command ကို ရိုက်သွင်းခြင်းဖြင့် Laravel ကို install ပြုလုပ်နိုင်မည် ဖြစ်သည်။ + + composer create-project laravel/laravel your-project-name --prefer-dist + +၄င်း command မှ laravel အသစ်စက်စက် ကို သင့်`your-project-name` folder အတွင်းတွင် တည်ရှိနေမည်ကို တွေ ့ရပါမည်။ + +ထိုတင်မက သင့် အနေဖြင့် [Laravel repository from Github](https://github.com/laravel/laravel/archive/master.zip) မှ ဒေါင်းလော့ ပြုလုပ်ပြီး directory ထဲတွင် `composer install` run ၍လည်း install ပြုလုပ်နိုင်ပါသည်။ ထို command မှ framework တွင် လိုအပ်သော package များကို အလိုအလျောက် download ပြုလုပ်ပြီး install သွားမည် ဖြစ်သည်။ + +### Permissions + +Laravel ကို install ပြုလုပ်ပြီးပါက သင့်အနေဖြင့် web server ၏ write permission ဖြင့်ပတ်သတ်၍ `app/storage` ထဲတွင် ပြင်ဆင်ရန် လိုအပ်ကောင်း လိုအပ်ပေမည်။ အသေးစိတ် အချက်အလက်ကို [Installation](installation.md) တွင် ကြည့်ရှုနိုင်ပါသည်။ + +### Serving Laravel + +အကြမ်းအားဖြင့် Apache သို ့မဟုတ် Nginx ပေါ်တွင် laravel application ကို တင်ထားနိုင်သည်။ သင့် အသုံးပြုသော PHP version မှာ 5.4 အထက်ဖြစ်ပြီး PHP တွင်ပါဝင်သော default server ကို အသုံးပြုလိုပါက သင့်အနေဖြင့် Artisan command ဖြစ်သည့် `serve` ကို အသုံးပြုနိုင်သည်။ + + php artisan serve + + +### Directory Structure + +Framework ကို install ပြုလုပ်ပြီးနောက် သင့် အနေဖြင့် directory structure ဖြင့် ရင်းနှီးနေရန် လိုပေမည်။ `app` directory ထဲတွင် `views`, `controllers`, and `models` အစရှိသည့် folder များ တည်ရှိနေသည်ကို တွေ ့ ရမည် ဖြစ်သည်။ သင့် application ၏ code များကို ထိုထဲတွင် ရေးသားရမည် ဖြစ်သည်။ သင့်အနေဖြင့် လိုအပ်မည့် configuration နှင့် ပတ်သတ်၍ `app/config` အမည်ရှိ directory ထဲတွင်ကြည့်ရှုရမည် ဖြစ်သည်။ + + +## Routing + +ရှေးဦးစွာ Route တစ်ခုကို တည်ဆောက်ကြပါစို ့။ Laravel တွင် အရိုးရှင်းဆုံး route မှာ route to Closure ဖြစ်သည်။ `app/routes.php` ကိုဖွင့်ပြီး အောက်ပါ code ကိုထည့်သွင်းကြည့်ပါ။ + + Route::get('users', function() + { + return 'Users!'; + }); + +ထိုနောက် web browser ပေါ်တွင် `/users` ဟူသော route ဖြင့် စမ်းကြည့်ပါက သင့်အနေဖြင့် `Users!` တုံ ့ပြန်သည်ကို မြင်တွေ ့ရမည် ဖြစ်သည်။ +ကောင်းလေစွ! သင့်အနေဖြင့် ပထမဦးစွာ route တစ်ခုကို ဖန်တီးလိုက်ပြီ ဖြစ်သည်။ + + +Route များမှာ controller များနှင့်လည်း ချိတ်ဆက် အလုပ်လုပ်နိုင်သည်။ ဥပမာ + + Route::get('users', 'UserController@getIndex'); + +အဆိုပါ route တွင် `/users` ဟုခေါ်ယူလိုက်ပါက `UserController` class အတွင်းရှိ `getIndex` method ကို အလုပ်လုပ်မည် ဖြစ်သည်။ Controller routing နှင့် ပတ်သတ်၍ အသေးစိတ်ကို [controller documentation](controllers.md) တွင်ကြည့်ရှုနိုင်သည်။ + + +## View တစ်ခု တည်ဆောက်ခြင်း + +ထိုနောက် user data များကို ဖော်ပြရန် ရိုးရှင်းသည့် view တစ်ခုကို တည်ဆောက်ရန် လိုပေမည်။ view file များသည် `app/views` directory ထဲတွင် တည်ရှိမည် ဖြစ်သည်။ View တွင် သင့် application တွင် ဖော်ပြလိုသည့် HTML ဖြင့် ဖော်ပြသွားမည် ဖြစ်သည်။ `layout.blade.php` နှင့် `users.blade.php` ဟု၍ file နှစ်ခုကို တည်ဆောက်လိုက်ပါ။ `layout.blade.php` ဟုသည့် file တွင် အောက်ပါ အတိုင်း ရေးသားလိုက်ပါ။ + + + +

    Laravel Quickstart

    + + @yield('content') + + + +ထိုနောက် `users.blade.php` ဟုသော view တစ်ခုကို တည်ဆောက် လတ္တံ ့။ + + @extends('layout') + + @section('content') + Users! + @stop + +တချို ့သော syntax များမှ သင့်အတွက် နည်းနည်း စိမ်းနေမည် ဖြစ်သည်။ အဘယ်ကြောင့်ဆိုသော် ယခု အသုံးပြုထားသည်မှာ Laravel ၏ templating system ဖြစ်သည့် Blade ကို အသုံးပြုထားခြင်း ကြောင့် ဖြစ်သည်။ Blade သည် အလွန်မြန်ဆန် လှပေသည်။ အကြောင်းမှာ ရိုးရှင်းလွယ်ကူ regular expression များကို အသုံးပြုကာ PHP အဖြစ်သို ့ compile ပြုလုပ်ထားခြင်းကြောင့်ဖြစ်သည်။ Blade အနေဖြင့် အလွန်တရာ စွမ်းအင်ကြီးမားလှသော template inheritance ကဲ့သို ့သော feature များကို support ပေးရုံသာမက PHP တွင် ရေးသားနိုင်သည့် `if` နှင့် `for` သို ့သော Conditional statement များကိုပါ သေသပ်လှပစွာ ရေးသားနိုင်သောကြောင့်ဖြစ်သည်။ အသေးစိတ်ကို [Blade documentation](templates.md) ကြည့်ရှုနိုင်ပေမည်။ + +ယခု ကျွန်တော်တို ့ views အပိုင်းကို ဖန်တီးပြီး ဖြစ်၍ `/users` ဟုသော route ဘက်ကို ပြန်လှည့်ကြပါစို ့။ Route မှ `Users!` ဟု return ပြန်ခြင်းထက် +view ကို ပြန်ပေးဖို ့လိုပေမည်။ + + Route::get('users', function() + { + return View::make('users'); + }); + +အံသြဖွယ်ကောင်းလေစွ။ သင့်အနေဖြင့် layout တစ်ခုကို extends ပြုလုပ်ထားသော view တစ်ခုကို တည်ဆောက်ပြီးပေသည်။ ဆက်၍ database layer တွင် ဆက်၍ လှုပ်ရှားကြပါစို ့။ + + +## Migration တစ်ခုဖန်တီးခြင်း + +Table တစ်ခုတည်ဆောက်ပြီး data တွေကို handle နိုင်ရန် Laravel migration system ကို အသုံးပြုရန်လိုပေမည်။ Migration အနေဖြင့် သင့် database ၏ modification ကို အလွယ်တကူ သတ်မှတ်နိုင်ပြီး သင့်အဖွဲ ့သားများနှင့် မျှဝေနိုင်ပေမည်။ + +ရှေးဦးစွာ database နှင့် ချိတ်ဆက်ရန် လိုပေမည်။ database ဖြင့်ချိတ်ဆက်ရန် အတွက် `app/config/database.php` တွင် ပြင်ဆင်ရန်လိုပေမည်။ ပုံမှန်အားဖြင့် Laravel သည် MySQL ဖြင့် အသုံးပြုရန် သတ်မှတ်ထားသည်။ သင့်အနေဖြင့် လိုအပ်သော credential များကို config file တွင် ဖြည့်သွင်းရန်လိုပေမည်။ သင့်အနေဖြင့် အလိုရှိပါက စိတ်ကြိုက် `driver` option ကို `sqlite` ဖြစ်စေပြောင်းလဲနိုင်ပြီ။ ၄င်းအနေဖြင့် `app/database` directory အောက်တွင် တည်ရှိမည့် SQLite database ကို အလုပ်လုပ်မည် ဖြစ်သည်။ + +ထိုနောက် migration တစ်ခု ဖန်တီးရန် [Artisan CLI](artisan.md) ကို အသုံးပြုမည် ဖြစ်သည်။ project ၏ root တွင် အောက်ပါ အတိုင်း terminal မှ run ရန် လိုပေမည်။ + + php artisan migrate:make create_users_table + +ဆက်၍ `app/database/migrations` တည်ရှိသည့် migration file ကို ရှာရန် လိုပေမည်။ ထိုထဲတွင် `up` နှင့်`down`ဟူသော method နှစ်ခုပါဝင်မည် ဖြစ်သည်။ + + +`up` method တွင် database တွင် ပြောင်းလဲချင်သည်များကို ထည့်သွင်းရေးသား၍ `down` method ပြောင်းပြန်ရေးသားရမည် ဖြစ်သည်။ +အောက်ပါအတိုင်း migration ကို တည်ဆောက်လိုက်ပါ။ + + public function up() + { + Schema::create('users', function($table) + { + $table->increments('id'); + $table->string('email')->unique(); + $table->string('name'); + $table->timestamps(); + }); + } + + public function down() + { + Schema::drop('users'); + } + +ဆက်၍ migrate ပြုလုပ်လိုပါက terminal တွင်`migrate` ဟုရိုက်ရန်လိုပေမည်။ + + php artisan migrate + +migration တစ်ခုကို rollback (နောက်ပြန်လှည့်) လိုပါက သင့်အနေဖြင့် `migrate:rollback` ဟူ၍ ရိုက်ရုံသာ ဖြစ်သည်။ ယခု database table ရှိပြီ ဖြစ်၍ +data လေးနည်းနည်းဖြင့် စလိုက်ကြပါစို ့။ + + +## Eloquent ORM + +Eloquent ORM သည် Laravel ၏ အလှတရား တစ်ရပ်ပင်ဖြစ်သည်။ သင့်အနေဖြင့် Ruby on Rails framework ကို အသုံးပြုဖူးပါက ၄င်းကဲ့သို ့ database interaction ပြုလုပ်ရာတွင် ActiveRecord ORM style သုံးထားသာ Eloquent နှင့်ရင်းနှီးနေမည် ဖြစ်သည်။ + +ပထမဦးဆုံး model တစ်ခုကို သတ်မှတ်ကြပါစို ့။ Eloquent model တစ်ခုသည် ဆက်စပ်နေသော database table များ၏ query ကိုပါ အသုံးပြုနိုင်သည်။ သိပ်များ နားရှုပ်သွားသလား မသိ။ အခုလာမယ့် အပိုင်းမှာ တဖြည်းဖြည်း နားလည်လာမှာပါ။ Model တွေဟာ `app/models` ဆိုတဲ့ directory အတွင်းမှာ တည်ရှိပါတယ်။ အဆိုပါ directory ထဲမှာ အောက်ပါအတိုင်း `User.php` ဆိုတဲ့ model တစ်ခုကို တည်ဆောက်လိုက်ပါ။ + + class User extends Eloquent {} + +သတိပြုရမည်မှာ ကျွန်တော်တို ့အနေဖြင့် Eloquent ကို မည်သည့် table အသုံးပြုရန် မညွန်းဆိုရသေးချေ။ Eloquent တွင် အသုံးပြုနည်း များစွာ ရှိသည့် အနက်တစ်ခုမှာ Model အမည်၏ အများကိန်းမှာ database table အဖြစ် အလိုအလျောက် သိရှိနေမည် ဖြစ်သည်။ အဆင်ပြေလေစွ! + +သင့်အနေဖြင့် ကြိုက်သည့် database administration tool ကို အသုံးပြုပြီး `users` table တွင် row အနည်းငယ် data သွင်းလိုက်ပါ။ ထိုနောက် Eloquent ကို အသုံးပြု၍ data များကို ထုတ်ယူပြီး view သို ့လွဲပြောင်းပေးလိုက်မည်။ + +ယခု `/users` route ကို အောက်ပါပုံစံပြောင်းလဲလိုက်ပါ။ + + Route::get('users', function() + { + $users = User::all(); + + return View::make('users')->with('users', $users); + }); + +အထက်ပါ route ကိုကြည့်ပါ။ ရှေးဦးစွာ `User` model မှ `all` method မှာ `users` table မှ rows အားလုံးကို ထုတ်ပေးမည် ဖြစ်သည်။ ထိုနောက် ထို record များကို `with` method အသုံးပြု၍ view သို ့ passing ပေးလိုက်ခြင်း ဖြစ်သည်။ ထို `with` method သည် key နှင့် value အနေဖြင့် data များကို လက်ခံမည် ဖြစ်သည်။ ထိုအခါ view သို ့ data များရောက်သွားမည် ဖြစ်သည်။ + +ကောင်းလေးစွ။ ယခု ကျွန်တော်တို ့ user ကို data များ ပြသနိုင်ရန် အဆင်သင့်ဖြစ်ချေပြီ။ + + +## Data များ ပြသခြင်း + +ယခုအခါ `users` ကို view တွင် မြင်သာစေရန် ပြုလုပ်ပြီးပြီဖြစ်သည်။ ကျွန်တော်တို ့ အောက်ပါ အတိုင်း ပြသနိုင်လေပြီ။ + + @extends('layout') + + @section('content') + @foreach($users as $user) +

    {{ $user->name }}

    + @endforeach + @stop + +သင့်အနေဖြင့် `echo` statements ကိုရှာနေလား မသိ။ Blade ကို အသုံးပြုရာတွင် data များကို တွန် ့ကွင်း နှစ်ခု အကြား ထည့်သွင်းခြင်းဖြင့် data များကို echo အစား ပြသပေးနိုင်သည်။ ဘယ်လောက်များ လွယ်ကူပေသလဲ။ ယခုအခါ သင့်အနေဖြင့် `/users` route ကို လှမ်းခေါ်လိုက်ခြင်းဖြင့် သင့် users များကို ပြသနိုင်လေပြီ။ + +အထက်ပါ ဥပမာဟာ အစသာရှိပါသေးသည်။ ထို tutorial တွင် သင့်အနေဖြင့် laravel ၏ အခြေခံကို တွေ ့မြင်နိုင်မည် ဖြစ်သည်။ သို ့သော်လည်း ပိုမို၍ စိတ်လှုပ်ရှားစရာ အချက်များစွာ စီတန်း၍ လေ့လာရန် ကျန်ရှိနေပါသေးသည်။ documentation ကို ဖတ်ရှုခြင်းဖြင့် စွမ်းအားကြီးမားလှသည့် [Eloquent](eloquent) နှင့် [Blade](/docs/templates) ကဲ့သို ့သော သို ့မဟုတ် သင့်ပိုစိတ်ဝင်စားနိုင်သည့် [Queues](/docs/queues) နှင့် [Unit Testing](/docs/testing) ကဲ့သို ့သော အကြောင်းအရာများကို လေ့လာနိုင်သည်။ ထပ်၍ သင့် application ၏ architecture ကို သက်တောင့်သက်သာ ဖြစ်စေမည့် [IoC Container](/docs/ioc.md) များလည်း ပါဝင်ပါသေးသည်။ ရွေးချယ်ပါလော့။ diff --git a/readme.md b/readme.md old mode 100644 new mode 100755 index 9b55bba..1da2956 --- a/readme.md +++ b/readme.md @@ -1,5 +1,15 @@ -# Laravel Documentation +ရည်ရွယ်ချက် +--------- -## Contribution Guidelines +ကျွန်တော်တို့ အခုမှစပြီး ဘာသာပြန်နေတုံးပါ၊ ရည်ရွယ်ချက် ကတော့ Laravel PHP Framework Documencation ကို မြန်မာလို ဖတ်ပြီး Laravel Framework ကို အလွယ်တကူ လေ့လာနိုင်ဖို့ပါ၊ + +ဒီဘာသာပြန်မှုမှာ ဘယ်လို ဘာဝင်ကူညီနိုင်လဲ +-------------------- + +ဟုတ်ကဲ့ ကျွန်တော်တို့လည်းအလုပ်နဲ့ပါ အားတဲ့အချိန်လေးဘာသာပြန်ပြီးတော့ဒီမှာတင်တာပါ။ တကယ်လို့ကျွန်တော်တို့ကို ကူညီပြီးဘာသာပြန်ချင်တယ်ဆိုရင်ဒီ Repo မှာ pull request လုပ်ပြီး contribute လုပ်နိုင်ပါတယ်။ ကျွန်တော်တို့ဘာသာပြန်ပြီးသားတွေကိုလည်း စာလုံးပေါင်းအမှားတွေကို git issue တွေပေးနိုင်ပါတယ်။ [Contribute Guide](contributing.md) ကိုဖတ်ပေးပါ။ + +ဆက်သွယ်ရန် +------- + +- [Laravel Myanmar Facebook Group](https://www.facebook.com/groups/250409601822202/) -If you are submitting documentation for the **current stable release**, submit it to the corresponding branch. For example, documentation for Laravel 5.1 would be submitted to the `5.1` branch. Documentation intended for the next release of Laravel should be submitted to the `master` branch. diff --git a/redirects.md b/redirects.md deleted file mode 100644 index e31c97b..0000000 --- a/redirects.md +++ /dev/null @@ -1,88 +0,0 @@ -# HTTP Redirects - -- [Creating Redirects](#creating-redirects) -- [Redirecting To Named Routes](#redirecting-named-routes) -- [Redirecting To Controller Actions](#redirecting-controller-actions) -- [Redirecting With Flashed Session Data](#redirecting-with-flashed-session-data) - - -## Creating Redirects - -Redirect responses are instances of the `Illuminate\Http\RedirectResponse` class, and contain the proper headers needed to redirect the user to another URL. There are several ways to generate a `RedirectResponse` instance. The simplest method is to use the global `redirect` helper: - - Route::get('dashboard', function () { - return redirect('home/dashboard'); - }); - -Sometimes you may wish to redirect the user to their previous location, such as when a submitted form is invalid. You may do so by using the global `back` helper function. Since this feature utilizes the [session](/docs/{{version}}/session), make sure the route calling the `back` function is using the `web` middleware group or has all of the session middleware applied: - - Route::post('user/profile', function () { - // Validate the request... - - return back()->withInput(); - }); - - -## Redirecting To Named Routes - -When you call the `redirect` helper with no parameters, an instance of `Illuminate\Routing\Redirector` is returned, allowing you to call any method on the `Redirector` instance. For example, to generate a `RedirectResponse` to a named route, you may use the `route` method: - - return redirect()->route('login'); - -If your route has parameters, you may pass them as the second argument to the `route` method: - - // For a route with the following URI: profile/{id} - - return redirect()->route('profile', ['id' => 1]); - -#### Populating Parameters Via Eloquent Models - -If you are redirecting to a route with an "ID" parameter that is being populated from an Eloquent model, you may simply pass the model itself. The ID will be extracted automatically: - - // For a route with the following URI: profile/{id} - - return redirect()->route('profile', [$user]); - -If you would like to customize the value that is placed in the route parameter, you should override the `getRouteKey` method on your Eloquent model: - - /** - * Get the value of the model's route key. - * - * @return mixed - */ - public function getRouteKey() - { - return $this->slug; - } - - -## Redirecting To Controller Actions - -You may also generate redirects to [controller actions](/docs/{{version}}/controllers). To do so, pass the controller and action name to the `action` method. Remember, you do not need to specify the full namespace to the controller since Laravel's `RouteServiceProvider` will automatically set the base controller namespace: - - return redirect()->action('HomeController@index'); - -If your controller route requires parameters, you may pass them as the second argument to the `action` method: - - return redirect()->action( - 'UserController@profile', ['id' => 1] - ); - - -## Redirecting With Flashed Session Data - -Redirecting to a new URL and [flashing data to the session](/docs/{{version}}/session#flash-data) are usually done at the same time. Typically, this is done after successfully performing an action when you flash a success message to the session. For convenience, you may create a `RedirectResponse` instance and flash data to the session in a single, fluent method chain: - - Route::post('user/profile', function () { - // Update the user's profile... - - return redirect('dashboard')->with('status', 'Profile updated!'); - }); - -After the user is redirected, you may display the flashed message from the [session](/docs/{{version}}/session). For example, using [Blade syntax](/docs/{{version}}/blade): - - @if (session('status')) -
    - {{ session('status') }} -
    - @endif diff --git a/redis.md b/redis.md old mode 100644 new mode 100755 index 7a52a36..a1270d1 --- a/redis.md +++ b/redis.md @@ -1,163 +1,88 @@ # Redis -- [Introduction](#introduction) - - [Configuration](#configuration) -- [Interacting With Redis](#interacting-with-redis) - - [Pipelining Commands](#pipelining-commands) -- [Pub / Sub](#pubsub) +- [အစပျိုး](#introduction) +- [Configuration](#configuration) +- [Usage](#usage) +- [Pipelining](#pipelining) -## Introduction +## အစပျိုး -[Redis](http://redis.io) is an open source, advanced key-value store. It is often referred to as a data structure server since keys can contain [strings](http://redis.io/topics/data-types#strings), [hashes](http://redis.io/topics/data-types#hashes), [lists](http://redis.io/topics/data-types#lists), [sets](http://redis.io/topics/data-types#sets), and [sorted sets](http://redis.io/topics/data-types#sorted-sets). Before using Redis with Laravel, you will need to install the `predis/predis` package via Composer: +[Redis](http://redis.io) သည် open source advanced key-value store တစ်ခုဖြစ်သည်။ ၄င်းသည် keys များတွင် [strings](http://redis.io/topics/data-types#strings), [hashes](http://redis.io/topics/data-types#hashes), [lists](http://redis.io/topics/data-types#lists), [sets](http://redis.io/topics/data-types#sets), and [sorted sets](http://redis.io/topics/data-types#sorted-sets) ပါဝင်သောကြောင့် ရံဖန်ရံခါ data structure server ဟု သတ်မှတ်ခြင်း ခံရသည်။ - composer require predis/predis +> **Note:** သင့်တွင် Redis PHP extension ကို PECL မှ တဆင့် သွင်းပြီးပါက Redis အတွက် အတိုကောက် အမည်ကို `app/config/app.php` ကြေညာပေးရမည်။ -### Configuration +## Configuration -The Redis configuration for your application is located in the `config/database.php` configuration file. Within this file, you will see a `redis` array containing the Redis servers utilized by your application: +Application အတွက် Redis configuration မှာ **app/config/database.php** အမည်ရှိ file ထဲတွင် တည်ရှိမည် ဖြစ်ပြီး ထို file ထဲတွင် **redis** +အမည်ရှိ array ကို application မှ အသုံးပြုမည် ဖြစ်သည်။ - 'redis' => [ - 'cluster' => false, + 'redis' => array( - 'default' => [ - 'host' => '127.0.0.1', - 'port' => 6379, - 'database' => 0, - ], + 'cluster' => true, - ], + 'default' => array('host' => '127.0.0.1', 'port' => 6379), -The default server configuration should suffice for development. However, you are free to modify this array based on your environment. Each Redis server defined in your configuration file is required to have a name, host, and port. + ), -The `cluster` option will instruct the Laravel Redis client to perform client-side sharding across your Redis nodes, allowing you to pool nodes and create a large amount of available RAM. However, note that client-side sharding does not handle failover; therefore, is primarily suited for cached data that is available from another primary data store. +default server configuration မှာ development အတွက် ဦးတည်ထားသော်လည်း မိမိတို ့စိတ်ကြိုက် ထို array ကိုပြောင်းလဲ သတ်မှတ်နိုင်သည်။ +ထို Redis server ၏ name ၊ host နှင့် Server မှ အသုံးပြုသည့် port ကို ကြေညာပေးရန်လိုပေမည်။ -Additionally, you may define an `options` array value in your Redis connection definition, allowing you to specify a set of Predis [client options](https://github.com/nrk/predis/wiki/Client-Options). -If your Redis server requires authentication, you may supply a password by adding a `password` configuration item to your Redis server configuration array. + Laravel Redis client ကို `cluster` option မှ Redis nodes များ အကြား client-side sharding ပြုလုပ်ရန် ညွန်ကြားခြင်းဖြင့် Nodes များမှ data ဆွဲယူပြီး RAM အတွက် နေရာလွတ်များ ဖန်တီးနိုင်မည် ဖြစ်သည်။ သို ့သော် client-side sharding သည် failover ကို ကိုင်တွယ်နိုင်ခြင်း မရှိပေ။ ထိုကြောင့် + Primary data store များ ရရှိနိုသည့် အခြေအနေတွင် cache data များ ထုတ်လွတ်ပေးသူ အဖြစ် အသုံးဝင်သည်။ -> {note} If you have the Redis PHP extension installed via PECL, you will need to rename the alias for Redis in your `config/app.php` file. +Redis Server အနေဖြင့် စိစစ်ရန်လိုအပ်ပါက Redis Server Configuration array အတွင်း `password` key / value pair ကို ထည့်သွင်းနိုင်သည်။ - -## Interacting With Redis + +## အသုံးပြုပုံ -You may interact with Redis by calling various methods on the `Redis` [facade](/docs/{{version}}/facades). The `Redis` facade supports dynamic methods, meaning you may call any [Redis command](http://redis.io/commands) on the facade and the command will be passed directly to Redis. In this example, we will call the Redis `GET` command by calling the `get` method on the `Redis` facade: - $user]); - } - } +Redis ၏ instance ကို ရရှိသည်နှင့် တပြိုင်နက် [Redis commands](http://redis.io/commands) ကို အသုံးပြုနိုင်ပြီ ဖြစ်သည်။ Laravel အနေဖြင့် magic methods ကို အသုံးပြုပြီး Redis server သို ့ command များကို ပို ့ဆောင်ပေးသည်။ -Of course, as mentioned above, you may call any of the Redis commands on the `Redis` facade. Laravel uses magic methods to pass the commands to the Redis server, so simply pass the arguments the Redis command expects: + $redis->set('name', 'Taylor'); - Redis::set('name', 'Taylor'); + $name = $redis->get('name'); - $values = Redis::lrange('names', 5, 10); + $values = $redis->lrange('names', 5, 10); -Alternatively, you may also pass commands to the server using the `command` method, which accepts the name of the command as its first argument, and an array of values as its second argument: - $values = Redis::command('lrange', ['name', 5, 10]); +အထက်က ဖော်ပြထားသည့် အတိုင်း Magic method များမှ command များကို passing ပေးသွားသည်ကို တွေ ့ရမည် ဖြစ်သည်။ သို ့သော် သင့်အနေဖြင့် Magic method များကို မသုံးမဖြစ် သုံးရသည် မဟုတ်ပဲ ၊ အသုံးမပြုလိုပါက `command` method ကို အစားထိုး အသုံးပြုနိုင်သည်။ -#### Using Multiple Redis Connections + $values = $redis->command('lrange', array(5, 10)); -You may get a Redis instance by calling the `Redis::connection` method: +default connection မှ ဆန် ့ကျင်ပြီး command များ အသုံးပြုလိုပါက `Redis` class မှ static magic method များကို အသုံးပြုနိုင်သည်။ - $redis = Redis::connection(); + Redis::set('name', 'Taylor'); -This will give you an instance of the default Redis server. If you are not using server clustering, you may pass the server name to the `connection` method to get a specific server as defined in your Redis configuration: + $name = Redis::get('name'); - $redis = Redis::connection('other'); + $values = Redis::lrange('names', 5, 10); - -### Pipelining Commands +> **Note:** Laravel တွင် Redis [cache](cache) နှင့် [session](/docs/session.md) drivers များ ပါဝင်ပြီး ဖြစ်သည်။ -Pipelining should be used when you need to send many commands to the server in one operation. The `pipeline` method accepts one argument: a `Closure` that receives a Redis instance. You may issue all of your commands to this Redis instance and they will all be executed within a single operation: + +## Pipelining - Redis::pipeline(function ($pipe) { - for ($i = 0; $i < 1000; $i++) { - $pipe->set("key:$i", $i); - } - }); +Operation တစ်ခုအတွက် Command များစွာ ကို ပို ့လွတ်ရန် လိုအပ်ပါက Pipelining ကို အသုံးပြုရသည်။ ထို သို ့ ပြုလုပ်ရန် `pipeline` ကို အသုံးပြုရမည်။ - -## Pub / Sub +#### Server သို ့ Command များကို Piping ပြုလုပ်ခြင်း -Laravel provides a convenient interface to the Redis `publish` and `subscribe` commands. These Redis commands allow you to listen for messages on a given "channel". You may publish messages to the channel from another application, or even using another programming language, allowing easy communication between applications and processes. - -First, let's setup a channel listener using the `subscribe` method. We'll place this method call within an [Artisan command](/docs/{{version}}/artisan) since calling the `subscribe` method begins a long-running process: - - 'bar'])); - }); - -#### Wildcard Subscriptions - -Using the `psubscribe` method, you may subscribe to a wildcard channel, which may be useful for catching all messages on all channels. The `$channel` name will be passed as the second argument to the provided callback `Closure`: - - Redis::psubscribe(['*'], function($message, $channel) { - echo $message; - }); - - Redis::psubscribe(['users.*'], function($message, $channel) { - echo $message; - }); + Redis::pipeline(function($pipe) + { + for ($i = 0; $i < 1000; $i++) + { + $pipe->set("key:$i", $i); + } + }); \ No newline at end of file diff --git a/releases.md b/releases.md old mode 100644 new mode 100755 index d31a832..f2f474c --- a/releases.md +++ b/releases.md @@ -1,505 +1,18 @@ # Release Notes -- [Support Policy](#support-policy) -- [Laravel 5.2](#laravel-5.2) -- [Laravel 5.1.11](#laravel-5.1.11) -- [Laravel 5.1.4](#laravel-5.1.4) -- [Laravel 5.1](#laravel-5.1) -- [Laravel 5.0](#laravel-5.0) - [Laravel 4.2](#laravel-4.2) - [Laravel 4.1](#laravel-4.1) - -## Support Policy - -For LTS releases, such as Laravel 5.1, bug fixes are provided for 2 years and security fixes are provided for 3 years. These releases provide the longest window of support and maintenance. - -For general releases, bug fixes are provided for 6 months and security fixes are provided for 1 year. - - -## Laravel 5.2 - -Laravel 5.2 continues the improvements made in Laravel 5.1 by adding multiple authentication driver support, implicit model binding, simplified Eloquent global scopes, opt-in authentication scaffolding, middleware groups, rate limiting middleware, array validation improvements, and more. - -### Authentication Drivers / "Multi-Auth" - -In previous versions of Laravel, only the default, session-based authentication driver was supported out of the box, and you could not have more than one authenticatable model instance per application. - -However, in Laravel 5.2, you may define additional authentication drivers as well define multiple authenticatable models or user tables, and control their authentication process separately from each other. For example, if your application has one database table for "admin" users and one database table for "student" users, you may now use the `Auth` methods to authenticate against each of these tables separately. - -### Authentication Scaffolding - -Laravel already makes it easy to handle authentication on the back-end; however, Laravel 5.2 provides a convenient, lightning-fast way to scaffold the authentication views for your front-end. Simply execute the `make:auth` command on your terminal: - - php artisan make:auth - -This command will generate plain, Bootstrap compatible views for user login, registration, and password reset. The command will also update your routes file with the appropriate routes. - -> {note} This feature is only meant to be used on new applications, not during application upgrades. - -### Implicit Model Binding - -Implicit model binding makes it painless to inject relevant models directly into your routes and controllers. For example, assume you have a route defined like the following: - - use App\User; - - Route::get('/user/{user}', function (User $user) { - return $user; - }); - -In Laravel 5.1, you would typically need to use the `Route::model` method to instruct Laravel to inject the `App\User` instance that matches the `{user}` parameter in your route definition. However, in Laravel 5.2, the framework will **automatically** inject this model based on the URI segment, allowing you to quickly gain access to the model instances you need. - -Laravel will automatically inject the model when the route parameter segment (`{user}`) matches the route Closure or controller method's corresponding variable name (`$user`) and the variable is type-hinting an Eloquent model class. - -### Middleware Groups - -Middleware groups allow you to group several route middleware under a single, convenient key, allowing you to assign several middleware to a route at once. For example, this can be useful when building a web UI and an API within the same application. You may group the session and CSRF routes into a `web` group, and perhaps the rate limiter in the `api` group. - -In fact, the default Laravel 5.2 application structure takes exactly this approach. For example, in the default `App\Http\Kernel.php` file you will find the following: - - /** - * The application's route middleware groups. - * - * @var array - */ - protected $middlewareGroups = [ - 'web' => [ - \App\Http\Middleware\EncryptCookies::class, - \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, - \Illuminate\Session\Middleware\StartSession::class, - \Illuminate\View\Middleware\ShareErrorsFromSession::class, - \App\Http\Middleware\VerifyCsrfToken::class, - ], - - 'api' => [ - 'throttle:60,1', - ], - ]; - -Then, the `web` group may be assigned to routes like so: - - Route::group(['middleware' => ['web']], function () { - // - }); - -However, keep in mind the `web` middleware group is *already* applied to your routes by default since the `RouteServiceProvider` includes it in the default middleware group. - -### Rate Limiting - -A new rate limiter middleware is now included with the framework, allowing you to easily limit the number of requests that a given IP address can make to a route over a specified number of minutes. For example, to limit a route to 60 requests every minute from a single IP address, you may do the following: - - Route::get('/api/users', ['middleware' => 'throttle:60,1', function () { - // - }]); - -### Array Validation - -Validating array form input fields is much easier in Laravel 5.2. For example, to validate that each e-mail in a given array input field is unique, you may do the following: - - $validator = Validator::make($request->all(), [ - 'person.*.email' => 'email|unique:users' - ]); - -Likewise, you may use the `*` character when specifying your validation messages in your language files, making it a breeze to use a single validation message for array based fields: - - 'custom' => [ - 'person.*.email' => [ - 'unique' => 'Each person must have a unique e-mail address', - ] - ], - -### Bail Validation Rule - -A new `bail` validation rule has been added, which instructs the validator to stop validating after the first validation failure for a given rule. For example, you may now prevent the validator from running a `unique` check if an attribute fails an `integer` check: - - $this->validate($request, [ - 'user_id' => 'bail|integer|unique:users' - ]); - -### Eloquent Global Scope Improvements - -In previous versions of Laravel, global Eloquent scopes were complicated and error-prone to implement; however, in Laravel 5.2, global query scopes only require you to implement a single, simple method: `apply`. - -For more information on writing global scopes, check out the full [Eloquent documentation](/docs/{{version}}/eloquent#global-scopes). - - -## Laravel 5.1.11 - -Laravel 5.1.11 introduces [authorization](/docs/{{version}}/authorization) support out of the box! Conveniently organize your application's authorization logic using simple callbacks or policy classes, and authorize actions using simple, expressive methods. - -For more information, please refer to the [authorization documentation](/docs/{{version}}/authorization). - - -## Laravel 5.1.4 - -Laravel 5.1.4 introduces simple login throttling to the framework. Consult the [authentication documentation](/docs/{{version}}/authentication#authentication-throttling) for more information. - - -## Laravel 5.1 - -Laravel 5.1 continues the improvements made in Laravel 5.0 by adopting PSR-2 and adding event broadcasting, middleware parameters, Artisan improvements, and more. - -### PHP 5.5.9+ - -Since PHP 5.4 will enter "end of life" in September and will no longer receive security updates from the PHP development team, Laravel 5.1 requires PHP 5.5.9 or greater. PHP 5.5.9 allows compatibility with the latest versions of popular PHP libraries such as Guzzle and the AWS SDK. - -### LTS - - Laravel 5.1 is the first release of Laravel to receive **long term support**. Laravel 5.1 will receive bug fixes for 2 years and security fixes for 3 years. This support window is the largest ever provided for Laravel and provides stability and peace of mind for larger, enterprise clients and customers. - -### PSR-2 - -The [PSR-2 coding style guide](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) has been adopted as the default style guide for the Laravel framework. Additionally, all generators have been updated to generate PSR-2 compatible syntax. - -### Documentation - -Every page of the Laravel documentation has been meticulously reviewed and dramatically improved. All code examples have also been reviewed and expanded to provide more relevance and context. - -### Event Broadcasting - -In many modern web applications, web sockets are used to implement real-time, live-updating user interfaces. When some data is updated on the server, a message is typically sent over a websocket connection to be handled by the client. - -To assist you in building these types of applications, Laravel makes it easy to "broadcast" your events over a websocket connection. Broadcasting your Laravel events allows you to share the same event names between your server-side code and your client-side JavaScript framework. - -To learn more about event broadcasting, check out the [event documentation](/docs/{{version}}/events#broadcasting-events). - -### Middleware Parameters - -Middleware can now receive additional custom parameters. For example, if your application needs to verify that the authenticated user has a given "role" before performing a given action, you could create a `RoleMiddleware` that receives a role name as an additional argument: - - user()->hasRole($role)) { - // Redirect... - } - - return $next($request); - } - - } - -Middleware parameters may be specified when defining the route by separating the middleware name and parameters with a `:`. Multiple parameters should be delimited by commas: - - Route::put('post/{id}', ['middleware' => 'role:editor', function ($id) { - // - }]); - -For more information on middleware, check out the [middleware documentation](/docs/{{version}}/middleware). - -### Testing Overhaul - -The built-in testing capabilities of Laravel have been dramatically improved. A variety of new methods provide a fluent, expressive interface for interacting with your application and examining its responses. For example, check out the following test: - - public function testNewUserRegistration() - { - $this->visit('/register') - ->type('Taylor', 'name') - ->check('terms') - ->press('Register') - ->seePageIs('/dashboard'); - } - -For more information on testing, check out the [testing documentation](/docs/{{version}}/testing). - -### Model Factories - -Laravel now ships with an easy way to create stub Eloquent models using [model factories](/docs/{{version}}/database-testing#writing-factories). Model factories allow you to easily define a set of "default" attributes for your Eloquent model, and then generate test model instances for your tests or database seeds. Model factories also take advantage of the powerful [Faker](https://github.com/fzaninotto/Faker) PHP library for generating random attribute data: - - $factory->define(App\User::class, function ($faker) { - return [ - 'name' => $faker->name, - 'email' => $faker->email, - 'password' => str_random(10), - 'remember_token' => str_random(10), - ]; - }); - -For more information on model factories, check out [the documentation](/docs/{{version}}/database-testing#writing-factories). - -### Artisan Improvements - -Artisan commands may now be defined using a simple, route-like "signature", which provides an extremely simple interface for defining command line arguments and options. For example, you may define a simple command and its options like so: - - /** - * The name and signature of the console command. - * - * @var string - */ - protected $signature = 'email:send {user} {--force}'; - -For more information on defining Artisan commands, consult the [Artisan documentation](/docs/{{version}}/artisan). - -### Folder Structure - -To better express intent, the `app/Commands` directory has been renamed to `app/Jobs`. Additionally, the `app/Handlers` directory has been consolidated into a single `app/Listeners` directory which simply contains event listeners. However, this is not a breaking change and you are not required to update to the new folder structure to use Laravel 5.1. - -### Encryption - -In previous versions of Laravel, encryption was handled by the `mcrypt` PHP extension. However, beginning in Laravel 5.1, encryption is handled by the `openssl` extension, which is more actively maintained. - - -## Laravel 5.0 - -Laravel 5.0 introduces a fresh application structure to the default Laravel project. This new structure serves as a better foundation for building a robust application in Laravel, as well as embraces new auto-loading standards (PSR-4) throughout the application. First, let's examine some of the major changes: - -### New Folder Structure - -The old `app/models` directory has been entirely removed. Instead, all of your code lives directly within the `app` folder, and, by default, is organized to the `App` namespace. This default namespace can be quickly changed using the new `app:name` Artisan command. - -Controllers, middleware, and requests (a new type of class in Laravel 5.0) are now grouped under the `app/Http` directory, as they are all classes related to the HTTP transport layer of your application. Instead of a single, flat file of route filters, all middleware are now broken into their own class files. - -A new `app/Providers` directory replaces the `app/start` files from previous versions of Laravel 4.x. These service providers provide various bootstrapping functions to your application, such as error handling, logging, route loading, and more. Of course, you are free to create additional service providers for your application. - -Application language files and views have been moved to the `resources` directory. - -### Contracts - -All major Laravel components implement interfaces which are located in the `illuminate/contracts` repository. This repository has no external dependencies. Having a convenient, centrally located set of interfaces you may use for decoupling and dependency injection will serve as an easy alternative option to Laravel Facades. - -For more information on contracts, consult the [full documentation](/docs/{{version}}/contracts). - -### Route Cache - -If your application is made up entirely of controller routes, you may utilize the new `route:cache` Artisan command to drastically speed up the registration of your routes. This is primarily useful on applications with 100+ routes and will **drastically** speed up this portion of your application. - -### Route Middleware - -In addition to Laravel 4 style route "filters", Laravel 5 now supports HTTP middleware, and the included authentication and CSRF "filters" have been converted to middleware. Middleware provides a single, consistent interface to replace all types of filters, allowing you to easily inspect, and even reject, requests before they enter your application. - -For more information on middleware, check out [the documentation](/docs/{{version}}/middleware). - -### Controller Method Injection - -In addition to the existing constructor injection, you may now type-hint dependencies on controller methods. The [service container](/docs/{{version}}/container) will automatically inject the dependencies, even if the route contains other parameters: - - public function createPost(Request $request, PostRepository $posts) - { - // - } - -### Authentication Scaffolding - -User registration, authentication, and password reset controllers are now included out of the box, as well as simple corresponding views, which are located at `resources/views/auth`. In addition, a "users" table migration has been included with the framework. Including these simple resources allows rapid development of application ideas without bogging down on authentication boilerplate. The authentication views may be accessed on the `auth/login` and `auth/register` routes. The `App\Services\Auth\Registrar` service is responsible for user validation and creation. - -### Event Objects - -You may now define events as objects instead of simply using strings. For example, check out the following event: - - podcast = $podcast; - } - } - -The event may be dispatched like normal: - - Event::fire(new PodcastWasPurchased($podcast)); - -Of course, your event handler will receive the event object instead of a list of data: - - user = $user; - $this->podcast = $podcast; - } - - /** - * Execute the command. - * - * @return void - */ - public function handle() - { - // Handle the logic to purchase the podcast... - - event(new PodcastWasPurchased($this->user, $this->podcast)); - } - } - -The base Laravel controller utilizes the new `DispatchesCommands` trait, allowing you to easily dispatch your commands for execution: - - $this->dispatch(new PurchasePodcastCommand($user, $podcast)); - -Of course, you may also use commands for tasks that are executed synchronously (are not queued). In fact, using commands is a great way to encapsulate complex tasks your application needs to perform. For more information, check out the [command bus](/docs/{{version}}/bus) documentation. - -### Database Queue - -A `database` queue driver is now included in Laravel, providing a simple, local queue driver that requires no extra package installation beyond your database software. - -### Laravel Scheduler - -In the past, developers have generated a Cron entry for each console command they wished to schedule. However, this is a headache. Your console schedule is no longer in source control, and you must SSH into your server to add the Cron entries. Let's make our lives easier. The Laravel command scheduler allows you to fluently and expressively define your command schedule within Laravel itself, and only a single Cron entry is needed on your server. - -It looks like this: - - $schedule->command('artisan:command')->dailyAt('15:00'); - -Of course, check out the [full documentation](/docs/{{version}}/scheduling) to learn all about the scheduler! - -### Tinker / Psysh - -The `php artisan tinker` command now utilizes [Psysh](https://github.com/bobthecow/psysh) by Justin Hileman, a more robust REPL for PHP. If you liked Boris in Laravel 4, you're going to love Psysh. Even better, it works on Windows! To get started, just try: - - php artisan tinker - -### DotEnv - -Instead of a variety of confusing, nested environment configuration directories, Laravel 5 now utilizes [DotEnv](https://github.com/vlucas/phpdotenv) by Vance Lucas. This library provides a super simple way to manage your environment configuration, and makes environment detection in Laravel 5 a breeze. For more details, check out the full [configuration documentation](/docs/{{version}}/installation#environment-configuration). - -### Laravel Elixir - -Laravel Elixir, by Jeffrey Way, provides a fluent, expressive interface to compiling and concatenating your assets. If you've ever been intimidated by learning Grunt or Gulp, fear no more. Elixir makes it a cinch to get started using Gulp to compile your Less, Sass, and CoffeeScript. It can even run your tests for you! - -For more information on Elixir, check out the [full documentation](/docs/{{version}}/elixir). - -### Laravel Socialite - -Laravel Socialite is an optional, Laravel 5.0+ compatible package that provides totally painless authentication with OAuth providers. Currently, Socialite supports Facebook, Twitter, Google, and GitHub. Here's what it looks like: - - public function redirectForAuth() - { - return Socialize::with('twitter')->redirect(); - } - - public function getUserFromProvider() - { - $user = Socialize::with('twitter')->user(); - } - -No more spending hours writing OAuth authentication flows. Get started in minutes! The [full documentation](/docs/{{version}}/authentication#social-authentication) has all the details. - -### Flysystem Integration - -Laravel now includes the powerful [Flysystem](https://github.com/thephpleague/flysystem) filesystem abstraction library, providing pain free integration with local, Amazon S3, and Rackspace cloud storage - all with one, unified and elegant API! Storing a file in Amazon S3 is now as simple as: - - Storage::put('file.txt', 'contents'); - -For more information on the Laravel Flysystem integration, consult the [full documentation](/docs/{{version}}/filesystem). - -### Form Requests - -Laravel 5.0 introduces **form requests**, which extend the `Illuminate\Foundation\Http\FormRequest` class. These request objects can be combined with controller method injection to provide a boiler-plate free method of validating user input. Let's dig in and look at a sample `FormRequest`: - - 'required|email|unique:users', - 'password' => 'required|confirmed|min:8', - ]; - } - - public function authorize() - { - return true; - } - } - -Once the class has been defined, we can type-hint it on our controller action: - - public function register(RegisterRequest $request) - { - var_dump($request->input()); - } - -When the Laravel service container identifies that the class it is injecting is a `FormRequest` instance, the request will **automatically be validated**. This means that if your controller action is called, you can safely assume the HTTP request input has been validated according to the rules you specified in your form request class. Even more, if the request is invalid, an HTTP redirect, which you may customize, will automatically be issued, and the error messages will be either flashed to the session or converted to JSON. **Form validation has never been more simple.** For more information on `FormRequest` validation, check out the [documentation](/docs/{{version}}/validation#form-request-validation). - -### Simple Controller Request Validation - -The Laravel 5 base controller now includes a `ValidatesRequests` trait. This trait provides a simple `validate` method to validate incoming requests. If `FormRequests` are a little too much for your application, check this out: - - public function createPost(Request $request) - { - $this->validate($request, [ - 'title' => 'required|max:255', - 'body' => 'required', - ]); - } - -If the validation fails, an exception will be thrown and the proper HTTP response will automatically be sent back to the browser. The validation errors will even be flashed to the session! If the request was an AJAX request, Laravel even takes care of sending a JSON representation of the validation errors back to you. - -For more information on this new method, check out [the documentation](/docs/{{version}}/validation#validation-quickstart). - -### New Generators - -To complement the new default application structure, new Artisan generator commands have been added to the framework. See `php artisan list` for more details. - -### Configuration Cache - -You may now cache all of your configuration in a single file using the `config:cache` command. - -### Symfony VarDumper - -The popular `dd` helper function, which dumps variable debug information, has been upgraded to use the amazing Symfony VarDumper. This provides color-coded output and even collapsing of arrays. Just try the following in your project: - - dd([1, 2, 3]); - ## Laravel 4.2 The full change list for this release by running the `php artisan changes` command from a 4.2 installation, or by [viewing the change file on Github](https://github.com/laravel/framework/blob/4.2/src/Illuminate/Foundation/changes.json). These notes only cover the major enhancements and changes for the release. -> {note} During the 4.2 release cycle, many small bug fixes and enhancements were incorporated into the various Laravel 4.1 point releases. So, be sure to check the change list for Laravel 4.1 as well! +> **Note:** During the 4.2 release cycle, many small bug fixes and enhancements were incorporated into the various Laravel 4.1 point releases. So, be sure to check the change list for Laravel 4.1 as well! ### PHP 5.4 Requirement -Laravel 4.2 requires PHP 5.4 or greater. This upgraded PHP requirement allows us to use new PHP features such as traits to provide more expressive interfaces for tools like [Laravel Cashier](/docs/billing). PHP 5.4 also brings significant speed and performance improvements over PHP 5.3. +Laravel 4.2 requires PHP 5.4 or greater. This PHP upgrade requirements allows us to use new PHP features such as traits to provide a more expressive interfaces for tools like [Laravel Cashier](billing.md). PHP 5.4 also brings significant speed and performance improvements over PHP 5.3. ### Laravel Forge @@ -511,11 +24,11 @@ More information about Laravel Forge can be found on the [official Forge website ### Laravel Homestead -Laravel Homestead is an official Vagrant environment for developing robust Laravel and PHP applications. The vast majority of the boxes' provisioning needs are handled before the box is packaged for distribution, allowing the box to boot extremely quickly. Homestead includes Nginx 1.6, PHP 5.6, MySQL, Postgres, Redis, Memcached, Beanstalk, Node, Gulp, Grunt, & Bower. Homestead includes a simple `Homestead.yaml` configuration file for managing multiple Laravel applications on a single box. +Laravel Homestead is an official Vagrant environment for developing robust Laravel and PHP applications. The vast majority of the boxes provisioning needs are handled before the box is packaged for distribution, allowing the box to boot extremely quickly. Homestead includes Nginx 1.6, PHP 5.5.12, MySQL, Postgres, Redis, Memcached, Beanstalk, Node, Gulp, Grunt, & Bower. Homestaed includes a simple `Homestead.yaml` configuration file or managing multiple Laravel applications on a single box. The default Laravel 4.2 installation now includes an `app/config/local/database.php` configuration file that is configured to use the Homestead database out of the box, making Laravel initial installation and configuration more convenient. -The official documentation has also been updated to include [Homestead documentation](/docs/homestead). +The official documentation has also been updated to include [Homestead documentation](homestead.md). ### Laravel Cashier @@ -523,9 +36,9 @@ Laravel Cashier is a simple, expressive library for managing subscription billin ### Daemon Queue Workers -The Artisan `queue:work` command now supports a `--daemon` option to start a worker in "daemon mode", meaning the worker will continue to process jobs without ever re-booting the framework. This results in a significant reduction in CPU usage at the cost of a slightly more complex application deployment process. +The Artisan `queue:work` command now supports a `--daemon` option to start a worker in "deamon mode", meaning the worker will continue to process jobs without ever re-booting the framework. This results in a significant reduction in CPU usage at the cost of a slightly more complex application deployment process. -More information about daemon queue workers can be found in the [queue documentation](/docs/queues#daemon-queue-worker). +More information about daemon queue workers can be found in the [queue documentation](queue#daemon-queue-workers.md). ### Mail API Drivers @@ -535,7 +48,7 @@ Laravel 4.2 introduces new Mailgun and Mandrill API drivers for the `Mail` funct A much cleaner architecture for "soft deletes" and other "global scopes" has been introduced via PHP 5.4 traits. This new architecture allows for the easier construction of similar global traits, and a cleaner separation of concerns within the framework itself. -More information on the new `SoftDeletingTrait` may be found in the [Eloquent documentation](/docs/eloquent#soft-deleting). +More information on the new `SoftDeletingTrait` may be found in the [Eloquent documentation](eloquent#soft-deleting.md). ### Convenient Auth & Remindable Traits @@ -558,7 +71,7 @@ The full change list for this release by running the `php artisan changes` comma ### New SSH Component -An entirely new `SSH` component has been introduced with this release. This feature allows you to easily SSH into remote servers and run commands. To learn more, consult the [SSH component documentation](/docs/ssh). +An entirely new `SSH` component has been introduced with this release. This feature allows you to easily SSH into remote servers and run commands. To learn more, consult the [SSH component documentation](ssh.md). The new `php artisan tail` command utilizes the new SSH component. For more information, consult the `tail` [command documentation](http://laravel.com/docs/ssh#tailing-remote-logs). @@ -568,13 +81,13 @@ The `php artisan tinker` command now utilizes the [Boris REPL](https://github.co ### Eloquent Improvements -A new `hasManyThrough` relationship has been added to Eloquent. To learn how to use it, consult the [Eloquent documentation](/docs/eloquent#has-many-through). +A new `hasManyThrough` relationship has been added to Eloquent. To learn how to use it, consult the [Eloquent documentation](eloquent#has-many-through.md). -A new `whereHas` method has also been introduced to allow [retrieving models based on relationship constraints](/docs/eloquent#querying-relations). +A new `whereHas` method has also been introduced to allow [retrieving models based on relationship constraints](eloquent#querying-relations.md). ### Database Read / Write Connections -Automatic handling of separate read / write connections is now available throughout the database layer, including the query builder and Eloquent. For more information, consult [the documentation](/docs/database#read-write-connections). +Automatic handling of separate read / write connections is now available throughout the database layer, including the query builder and Eloquent. For more information, consult [the documentation](database#read-write-connections.md). ### Queue Priority @@ -582,15 +95,15 @@ Queue priorities are now supported by passing a comma-delimited list to the `que ### Failed Queue Job Handling -The queue facilities now include automatic handling of failed jobs when using the new `--tries` switch on `queue:listen`. More information on handling failed jobs can be found in the [queue documentation](/docs/queues#failed-jobs). +The queue facilities now include automatic handling of failed jobs when using the new `--tries` switch on `queue:listen`. More information on handling failed jobs can be found in the [queue documentation](queues#failed-jobs.md). ### Cache Tags -Cache "sections" have been superseded by "tags". Cache tags allow you to assign multiple "tags" to a cache item, and flush all items assigned to a single tag. More information on using cache tags may be found in the [cache documentation](/docs/cache#cache-tags). +Cache "sections" have been superseded by "tags". Cache tags allow you to assign multiple "tags" to a cache item, and flush all items assigned to a single tag. More information on using cache tags may be found in the [cache documentation](cache#cache-tags.md). ### Flexible Password Reminders -The password reminder engine has been changed to provide greater developer flexibility when validating passwords, flashing status messages to the session, etc. For more information on using the enhanced password reminder engine, [consult the documentation](/docs/security#password-reminders-and-reset). +The password reminder engine has been changed to provide greater developer flexibility when validating passwords, flashing status messages to the session, etc. For more information on using the enhanced password reminder engine, [consult the documentation](security#password-reminders-and-reset.md). ### Improved Routing Engine @@ -602,4 +115,4 @@ With this release, we're also introducing an entirely new session engine. Simila ### Doctrine DBAL -If you are using the `renameColumn` function in your migrations, you will need to add the `doctrine/dbal` dependency to your `composer.json` file. This package is no longer included in Laravel by default. +If you are using the `renameColumn` function in your migrations, you will need to add the `doctrine/dbal` dependency to your `composer.json` file. This package is no longer included in Laravel by default. \ No newline at end of file diff --git a/requests.md b/requests.md old mode 100644 new mode 100755 index 58102fd..42b52f9 --- a/requests.md +++ b/requests.md @@ -1,316 +1,224 @@ -# HTTP Requests - -- [Accessing The Request](#accessing-the-request) - - [Request Path & Method](#request-path-and-method) - - [PSR-7 Requests](#psr7-requests) -- [Retrieving Input](#retrieving-input) - - [Old Input](#old-input) - - [Cookies](#cookies) -- [Files](#files) - - [Retrieving Uploaded Files](#retrieving-uploaded-files) - - [Storing Uploaded Files](#storing-uploaded-files) - - -## Accessing The Request - -To obtain an instance of the current HTTP request via dependency injection, you should type-hint the `Illuminate\Http\Request` class on your controller method. The incoming request instance will automatically be injected by the [service container](/docs/{{version}}/container): - - input('name'); - - // - } - } - -#### Dependency Injection & Route Parameters - -If your controller method is also expecting input from a route parameter you should list your route parameters after your other dependencies. For example, if your route is defined like so: - - Route::put('user/{id}', 'UserController@update'); - -You may still type-hint the `Illuminate\Http\Request` and access your route parameter `id` by defining your controller method as follows: - - -### Request Path & Method - -The `Illuminate\Http\Request` instance provides a variety of methods for examining the HTTP request for your application and extends the `Symfony\Component\HttpFoundation\Request` class. We will discuss a few of the most important methods below. +# Requests နှင့် Input များအကြောင်း -#### Retrieving The Request Path - -The `path` method returns the request's path information. So, if the incoming request is targeted at `http://domain.com/foo/bar`, the `path` method will return `foo/bar`: - - $uri = $request->path(); - -The `is` method allows you to verify that the incoming request path matches a given pattern. You may use the `*` character as a wildcard when utilizing this method: - - if ($request->is('admin/*')) { - // - } - -#### Retrieving The Request URL - -To retrieve the full URL for the incoming request you may use the `url` or `fullUrl` methods. The `url` method will return the URL without the query string, while the `fullUrl` method includes the query string: - - // Without Query String... - $url = $request->url(); - - // With Query String... - $url = $request->fullUrl(); - -#### Retrieving The Request Method - -The `method` method will return the HTTP verb for the request. You may use the `isMethod` method to verify that the HTTP verb matches a given string: - - $method = $request->method(); - - if ($request->isMethod('post')) { - // - } +- [Basic Input](#basic-input) +- [Cookies](#cookies) +- [Old Input](#old-input) +- [Files](#files) +- [Request Information](#request-information) - -### PSR-7 Requests + +## Basic Input -The [PSR-7 standard](http://www.php-fig.org/psr/psr-7/) specifies interfaces for HTTP messages, including requests and responses. If you would like to obtain an instance of a PSR-7 request instead of a Laravel request, you will first need to install a few libraries. Laravel uses the *Symfony HTTP Message Bridge* component to convert typical Laravel requests and responses into PSR-7 compatible implementations: +You may access all user input with a few simple methods. You do not need to worry about the HTTP verb used for the request, as input is accessed in the same way for all verbs. - composer require symfony/psr-http-message-bridge - composer require zendframework/zend-diactoros +Http verb တွေအားလုံးက input ဆီကို ဝင်ရောက်လာတဲ့အချိန်မှာ Simple methods တွေနဲ့ users အားလုံးရဲ့ input တွေကို access လုပ်နိုင်ပါတယ်။ Request တွေအတွက် HTTP verb တွေကိုစိုးရိမ်စရာမလိုပါဘူး။ -Once you have installed these libraries, you may obtain a PSR-7 request by type-hinting the request interface on your route Closure or controller method: +#### Input Value တစ်ခုကိုပြန်လည်ရချင်ရင် - use Psr\Http\Message\ServerRequestInterface; + $name = Input::get('name'); - Route::get('/', function (ServerRequestInterface $request) { - // - }); +#### Input မှာ Value မရှိသေးဘဲ Default Value ပြချင်ရင် - -> {tip} If you return a PSR-7 response instance from a route or controller, it will automatically be converted back to a Laravel response instance and be displayed by the framework. + $name = Input::get('name', 'Sally'); - -## Retrieving Input +#### Input Value ရှိတာကိုဆုံးဖြတ်ဖို့- -#### Retrieving All Input Data + if (Input::has('name')) + { + // + } -You may also retrieve all of the input data as an `array` using the `all` method: +#### Input အားလုံးရဲ့ Request ကိုရချင်ရင်- - $input = $request->all(); + $input = Input::all(); -#### Retrieving An Input Value +#### Input တစ်ချို့ရဲ့ Request အားလုံးကိုရချင်ရင်- -Using a few simple methods, you may access all of the user input from your `Illuminate\Http\Request` instance without worrying about which HTTP verb was used for the request. Regardless of the HTTP verb, the `input` method may be used to retrieve user input: + $input = Input::only('username', 'password'); - $name = $request->input('name'); + $input = Input::except('credit_card'); -You may pass a default value as the second argument to the `input` method. This value will be returned if the requested input value is not present on the request: +When working on forms with "array" inputs, you may use dot notation to access the arrays: +Form တွေကို arrays input တွေနဲ့အသုံးပြုတဲ့အခါမှာ arrays တွေကို access လုပ်ဖို့ "." သင်္ကေတကိုအသုံးပြုရပါမယ်။ - $name = $request->input('name', 'Sally'); + $input = Input::get('products.0.name'); -When working with forms that contain array inputs, use "dot" notation to access the arrays: +> **Note:** Some JavaScript libraries such as Backbone may send input to the application as JSON. You may access this data via `Input::get` like normal. - $name = $request->input('products.0.name'); + +## Cookies - $names = $request->input('products.*.name'); +Cookies အားလုံးကို Laravel Framework က authernication code နဲ့ encrypted လုပ်ထားပါတယ်၊ ဒါကဘာကိုဆိုလိုတာလဲဆိုရင် cookie တွေကို client ကပြောင်းလိုက်ပြီဆိုရင် သူတို့တရားမဝင်တာကိုနားလည်လိမ့်မယ်။ -#### Retrieving Input Via Dynamic Properties +#### Cookie တစ်ခုရဲ့ Value ကိုရချင်ရင် -You may also access user input using dynamic properties on the `Illuminate\Http\Request` instance. For example, if one of your application's forms contains a `name` field, you may access the value of the field like so: + $value = Cookie::get('name'); - $name = $request->name; +#### Response တစ်ခုဆီကို Cookie အသစ်တစ်ခု attach လုပ်ချင်ရင် - -When using dynamic properties, Laravel will first look for the parameter's value in the request payload. If it is not present, Laravel will search for the field in the route parameters. + $response = Response::make('Hello World'); -#### Retrieving JSON Input Values + $response->withCookie(Cookie::make('name', 'value', $minutes)); -When sending JSON requests to your application, you may access the JSON data via the `input` method as long as the `Content-Type` header of the request is properly set to `application/json`. You may even use "dot" syntax to dig into JSON arrays: +#### နောက် Response တစ်ခုအတွက် Cookie တစ်ခုကို Queue လုပ်ခြင်း +Response မလုပ်ခင်မှာ cookie တစ်ခုကို set ချင်တယ်ဆို့င်ရင် `Cookie::queue()` method ကိုသုံးပါ။ သင့် application မှ နောက်ဆုံး response ကို cookie က အလိုလို attach လုပ်သွားပါလိမ့်မယ်။ - $name = $request->input('user.name'); + Cookie::queue($name, $value, $minutes); -#### Retrieving A Portion Of The Input Data +#### Creating A Cookie That Lasts Forever -If you need to retrieve a subset of the input data, you may use the `only` and `except` methods. Both of these methods accept a single `array` or a dynamic list of arguments: + $cookie = Cookie::forever('name', 'value'); - $input = $request->only(['username', 'password']); + +## Old Input - $input = $request->only('username', 'password'); +သင့်အနေနဲ့ request တစ်ခုကနေ တစ်ခု အကူးအပြောင်းအထိ input တွေကိုထိမ်းသိမ်းထားချင်ပါလိမ့်မယ်... ဥပမာ သင့်အနေနဲ့ form input တွေကို validation လုပ်ပြီး errors message နဲ့အတူ input တွေကိုပြန်ပြတဲ့ အချိန်မျိုးပေါ့။ - $input = $request->except(['credit_card']); +#### Flashing Input To The Session - $input = $request->except('credit_card'); + Input::flash(); -#### Determining If An Input Value Is Present +#### Flashing Only Some Input To The Session -You should use the `has` method to determine if a value is present on the request. The `has` method returns `true` if the value is present and is not an empty string: + Input::flashOnly('username', 'email'); - if ($request->has('name')) { - // - } + Input::flashExcept('password'); - -### Old Input +Since you often will want to flash input in association with a redirect to the previous page, you may easily chain input flashing onto a redirect. -Laravel allows you to keep input from one request during the next request. This feature is particularly useful for re-populating forms after detecting validation errors. However, if you are using Laravel's included [validation features](/docs/{{version}}/validation), it is unlikely you will need to manually use these methods, as some of Laravel's built-in validation facilities will call them automatically. + return Redirect::to('form')->withInput(); -#### Flashing Input To The Session + return Redirect::to('form')->withInput(Input::except('password')); -The `flash` method on the `Illuminate\Http\Request` class will flash the current input to the [session](/docs/{{version}}/session) so that it is available during the user's next request to the application: +> **Note:** You may flash other data across requests using the [Session](session.md) class. - $request->flash(); +#### Input Data အဟောင်းတွေကိုပြန်ကြည့်ချင်ရင် - -You may also use the `flashOnly` and `flashExcept` methods to flash a subset of the request data to the session. These methods are useful for keeping sensitive information such as passwords out of the session: + Input::old('username'); - $request->flashOnly(['username', 'email']); + +## Files - $request->flashExcept('password'); +#### File Upload တစ်ခုကိုပြန်ကြည့်ချင်ရင် - -#### Flashing Input Then Redirecting + $file = Input::file('photo'); -Since you often will want to flash input to the session and then redirect to the previous page, you may easily chain input flashing onto a redirect using the `withInput` method: +#### File upload လုပ်သွားလား မသွားလား ဆုံးဖြတ်ခြင်ရင် - return redirect('form')->withInput(); + if (Input::hasFile('photo')) + { + // + } - return redirect('form')->withInput( - $request->except('password') - ); +The object returned by the `file` method is an instance of the `Symfony\Component\HttpFoundation\File\UploadedFile` class, which extends the PHP `SplFileInfo` class and provides a variety of methods for interacting with the file. -#### Retrieving Old Input +#### File Upload လုပ်တာမှားလားစစ်ချင်ရင် - -To retrieve flashed input from the previous request, use the `old` method on the `Request` instance. The `old` method will pull the previously flashed input data from the [session](/docs/{{version}}/session): + if (Input::file('photo')->isValid()) + { + // + } - $username = $request->old('username'); +#### Upload File ကို Move လုပ်ချင်ရင် -Laravel also provides a global `old` helper. If you are displaying old input within a [Blade template](/docs/{{version}}/blade), it is more convenient to use the `old` helper. If no old input exists for the given field, `null` will be returned: + Input::file('photo')->move($destinationPath); - + Input::file('photo')->move($destinationPath, $fileName); - -### Cookies +#### File Upload လုပ်သွားတဲ့ လမ်းကြောင်းရချင်ရင် - -#### Retrieving Cookies From Requests + $path = Input::file('photo')->getRealPath(); -All cookies created by the Laravel framework are encrypted and signed with an authentication code, meaning they will be considered invalid if they have been changed by the client. To retrieve a cookie value from the request, use the `cookie` method on a `Illuminate\Http\Request` instance: +#### Upload File ရဲ့ မူလအမည်ကိုရချင်ရင် - - $value = $request->cookie('name'); + $name = Input::file('photo')->getClientOriginalName(); -#### Attaching Cookies To Responses +#### Upload File ရဲ့ extension ကိုသိချင်ရင် -You may attach a cookie to an outgoing `Illuminate\Http\Response` instance using the `cookie` method. You should pass the name, value, and number of minutes the cookie should be considered valid to this method: + $extension = Input::file('photo')->getClientOriginalExtension(); - return response('Hello World')->cookie( - 'name', 'value', $minutes - ); +#### Upload လုပ်လိုက်တဲ့ File Size ကိုသိချင်ရင် -The `cookie` method also accepts a few more arguments which are used less frequently. Generally, these arguments have the same purpose and meaning as the arguments that would be given to PHP's native [setcookie](http://php.net/manual/en/function.setcookie.php) method: + $size = Input::file('photo')->getSize(); - return response('Hello World')->cookie( - 'name', 'value', $minutes, $path, $domain, $secure, $httpOnly - ); +#### Upload File ရဲ့ MIME Type ကိုသိချင်ရင် -#### Generating Cookie Instances + $mime = Input::file('photo')->getMimeType(); -If you would like to generate a `Symfony\Component\HttpFoundation\Cookie` instance that can be given to a response instance at a later time, you may use the global `cookie` helper. This cookie will not be sent back to the client unless it is attached to a response instance: + +## Request Information - $cookie = cookie('name', 'value', $minutes); +The `Request` class provides many methods for examining the HTTP request for your application and extends the `Symfony\Component\HttpFoundation\Request` class. Here are some of the highlights. - return response('Hello World')->cookie($cookie); +#### Request URI ရဲ့ လမ်းကြောင်းကိုသိချင်ရင် - -### Files + $uri = Request::path(); - -### Retrieving Uploaded Files +#### Request Method ကို retrieving လုပ်ချင်ရင် -You may access uploaded files from a `Illuminate\Http\Request` instance using the `file` method or using dynamic properties. The `file` method returns an instance of the `Illuminate\Http\UploadedFile` class, which extends the PHP `SplFileInfo` class and provides a variety of methods for interacting with the file: + $method = Request::method(); - $file = $request->file('photo'); + if (Request::isMethod('post')) + { + // + } - $file = $request->photo; +#### Request လမ်းကြောင်းက pattern တစ်ခုနဲ့ mathces ဖြစ်လားဆိုတာကိုဆုံးဖြတ်ချင်ရင် - -You may determine if a file is present on the request using the `hasFile` method: + if (Request::is('admin/*')) + { + // + } - if ($request->hasFile('photo')) { - // - } +#### Request URL ကိုရယူခြင်ရင် -#### Validating Successful Uploads + $url = Request::url(); -In addition to checking if the file is present, you may verify that there were no problems uploading the file via the `isValid` method: +#### Request URI segment ကို retrieve လုပ်ချင်ရင် - if ($request->file('photo')->isValid()) { - // - } + $segment = Request::segment(1); -#### File Paths & Extensions +#### Request Header ကိုရချင်ရင် - -The `UploadedFile` class also contains methods for accessing the file's fully-qualified path and its extension. The `extension` method will attempt to guess the file's extension based on its contents. This extension may be different from the extension that was supplied by the client: + $value = Request::header('Content-Type'); - $path = $request->photo->path(); +#### Retrieving Values From $_SERVER - $extension = $request->photo->extension(); + $value = Request::server('PATH_INFO'); -#### Other File Methods +#### Request က HTTPS ကလားဆိုတာကိုစစ်ချင်ရင် - -There are a variety of other methods available on `UploadedFile` instances. Check out the [API documentation for the class](http://api.symfony.com/3.0/Symfony/Component/HttpFoundation/File/UploadedFile.html) for more information regarding these methods. + if (Request::secure()) + { + // + } - -### Storing Uploaded Files +#### Request က AJAX သုံးထားလားဆိုတာကိုစစ်ချင်ရင် -To store an uploaded file, you will typically use one of your configured [filesystems](/docs/{{version}}/filesystem). The `UploadedFile` class has a `store` method which will move an uploaded file to one of your disks, which may be a location on your local filesystem or even a cloud storage location like Amazon S3. + if (Request::ajax()) + { + // + } -The `store` method accepts the path where the file should be stored relative to the filesystem's configured root directory. This path should not contain a file name, since the name will automatically be generated using the MD5 hash of the file's contents. +#### Request မှာ JSON Content Type ရှိလားဆိုတာကိုစစ်ချင်ရင် -The `store` method also accepts an optional second argument for the name of the disk that should be used to store the file. The method will return the path of the file relative to the disk's root: + if (Request::isJson()) + { + // + } - $path = $request->photo->store('images'); +#### Request က JSON ကို တောင်းလားဆိုတာကိုစစ်ချင်ရင် - $path = $request->photo->store('images', 's3'); + if (Request::wantsJson()) + { + // + } -If you do not want a file name to be automatically generated, you may use the `storeAs` method, which accepts the path, file name, and disk name as its arguments: +#### Request ရဲ့ Response ကို Check လုပ်ချင်ရင် - $path = $request->photo->storeAs('images', 'filename.jpg'); +The `Request::format` method will return the requested response format based on the HTTP Accept header: - $path = $request->photo->storeAs('images', 'filename.jpg', 's3'); + if (Request::format() == 'json') + { + // + } diff --git a/responses.md b/responses.md old mode 100644 new mode 100755 index e7d45b4..5e4ae9d --- a/responses.md +++ b/responses.md @@ -1,257 +1,228 @@ -# HTTP Responses +# Views နှင့် Responses များအကြောင်း -- [Creating Responses](#creating-responses) - - [Attaching Headers To Responses](#attaching-headers-to-responses) - - [Attaching Cookies To Responses](#attaching-cookies-to-responses) - - [Cookies & Encryption](#cookies-and-encryption) +- [Basic Responses](#basic-responses) - [Redirects](#redirects) - - [Redirecting To Named Routes](#redirecting-named-routes) - - [Redirecting To Controller Actions](#redirecting-controller-actions) - - [Redirecting With Flashed Session Data](#redirecting-with-flashed-session-data) -- [Other Response Types](#other-response-types) - - [View Responses](#view-responses) - - [JSON Responses](#json-responses) - - [File Downloads](#file-downloads) - - [File Responses](#file-responses) +- [Views](#views) +- [View Composers](#view-composers) +- [Special Responses](#special-responses) - [Response Macros](#response-macros) - -## Creating Responses + +## Basic Responses -#### Strings & Arrays +#### String တစ်ခုကို Routes ကနေ return ပြန်ချင်ရင် - -All routes and controllers should return a response to be sent back to the user's browser. Laravel provides several different ways to return responses. The most basic response is simply returning a string from a route or controller. The framework will automatically convert the string into a full HTTP response: + Route::get('/', function() + { + return 'Hello World'; + }); - Route::get('/', function () { - return 'Hello World'; - }); +#### Creating Custom Responses -In addition to returning strings from your routes and controllers, you may also return arrays. The framework will automatically convert the array into a JSON response: +Symfony\Component\HttpFoundation\Response` class ကနေ Response` တစ်ခုကဖြစ်လာတယ်၊ HTTPS responses တွေကို တည်ဆောက်ဖို့ရာအတွက် များစွာသော methods တွေကနေ စီစဉ်ပေးပါတယ်။ - Route::get('/', function () { - return [1, 2, 3]; - }); + $response = Response::make($contents, $statusCode); -> {tip} Did you know you can also return [Eloquent collections](/docs/{{version}}/eloquent-collections) from your routes or controllers? They will automatically be converted to JSON. Give it a shot! + $response->header('Content-Type', $value); -#### Response Objects + return $response; -Typically, you won't just be returning simple strings or arrays from your route actions. Instead, you will be returning full `Illuminate\Http\Response` instances or [views](/docs/{{version}}/views). +သင်က `Response` class တစ်ခုရဲ့ method ကိုလည်းလိုချင်တယ်... ဒါပေမယ့် response content အဖြစ် return ပြန်ချင်တယ် ဆိုရင်တော့`Response::view` method ကအဆင်ပြေပါလိမ့်မယ်- -Returning a full `Response` instance allows you to customize the response's HTTP status code and headers. A `Response` instance inherits from the `Symfony\Component\HttpFoundation\Response` class, which provides a variety of methods for building HTTP responses: + return Response::view('hello')->header('Content-Type', $type); - Route::get('home', function () { - return response('Hello World', 200) - ->header('Content-Type', 'text/plain'); - }); +#### Cookies တွေကို Responses တွေဆီပြန်ချင်တယ်ဆိုရင် - -#### Attaching Headers To Responses + $cookie = Cookie::make('name', 'value'); -Keep in mind that most response methods are chainable, allowing for the fluent construction of response instances. For example, you may use the `header` method to add a series of headers to the response before sending it back to the user: + return Response::make($content)->withCookie($cookie); - return response($content) - ->header('Content-Type', $type) - ->header('X-Header-One', 'Header Value') - ->header('X-Header-Two', 'Header Value'); + +## ပြန်လည်လမ်းကြောင်းညွှန်ကြားမှူ့ -Or, you may use the `withHeaders` method to specify an array of headers to be added to the response: +#### Redirect လုပ်ချင်တယ်ဆိုရင် - - return response($content) - ->withHeaders([ - 'Content-Type' => $type, - 'X-Header-One' => 'Header Value', - 'X-Header-Two' => 'Header Value', - ]); + return Redirect::to('user/login'); - -#### Attaching Cookies To Responses +#### Flash Data နဲ့ Redirect လုပ်ရင် - -The `cookie` method on response instances allows you to easily attach cookies to the response. For example, you may use the `cookie` method to generate a cookie and fluently attach it to the response instance like so: + return Redirect::to('user/login')->with('message', 'Login Failed'); - return response($content) - ->header('Content-Type', $type) - ->cookie('name', 'value', $minutes); +> **Note:** Since the `with` method flashes data to the session, you may retrieve the data using the typical `Session::get` method. -The `cookie` method also accepts a few more arguments which are used less frequently. Generally, these arguments have the same purpose and meaning as the arguments that would be given to PHP's native [setcookie](http://php.net/manual/en/function.setcookie.php) method: +#### Nmaed Route နှင့် Redirect လုပ်ရင်- - ->cookie($name, $value, $minutes, $path, $domain, $secure, $httpOnly) + return Redirect::route('login'); - -#### Cookies & Encryption +#### Route Parameters တစ်ခုနဲ့ Redirect လုပ်ရင် - -By default, all cookies generated by Laravel are encrypted and signed so that they can't be modified or read by the client. If you would like to disable encryption for a subset of cookies generated by your application, you may use the `$except` property of the `App\Http\Middleware\EncryptCookies` middleware, which is located in the `app/Http/Middleware` directory: - /** - * The names of the cookies that should not be encrypted. - * - * @var array - */ - protected $except = [ - 'cookie_name', - ]; + return Redirect::route('profile', array(1)); - -## Redirects +#### Route ထဲမှာ name parameters ပါတာကို Redirect လုပ်ရင် -Redirect responses are instances of the `Illuminate\Http\RedirectResponse` class, and contain the proper headers needed to redirect the user to another URL. There are several ways to generate a `RedirectResponse` instance. The simplest method is to use the global `redirect` helper: + return Redirect::route('profile', array('user' => 1)); - Route::get('dashboard', function () { - return redirect('home/dashboard'); - }); +#### Controller ရဲ့ Action တစ်ခုကနေ Redirect တစ်ခု return လုပ်ချင်ရင် -Sometimes you may wish to redirect the user to their previous location, such as when a submitted form is invalid. You may do so by using the global `back` helper function. Since this feature utilizes the [session](/docs/{{version}}/session), make sure the route calling the `back` function is using the `web` middleware group or has all of the session middleware applied: + return Redirect::action('HomeController@index'); - Route::post('user/profile', function () { - // Validate the request... +#### Paramater ပါတဲ့ Controller တစ်ခုကို Redirect တစ်ခု return လုပ်ခြင်း - return back()->withInput(); - }); + return Redirect::action('UserController@profile', array(1)); - -### Redirecting To Named Routes +#### Name Parameters တစ်ခုပါတဲ့ Controller Action တစ်ခုကနေ Redirect တစ်ခု return လုပ်ခြင်း -When you call the `redirect` helper with no parameters, an instance of `Illuminate\Routing\Redirector` is returned, allowing you to call any method on the `Redirector` instance. For example, to generate a `RedirectResponse` to a named route, you may use the `route` method: + return Redirect::action('UserController@profile', array('user' => 1)); - return redirect()->route('login'); + +## Views -If your route has parameters, you may pass them as the second argument to the `route` method: +သင့်ရဲ့ presentation logic ကနေ controller နဲ့ domain logic တွေ ခွဲခြားဖို့ရာအတွက် Views က အဆင်ပြေဆုံးဖြစ်အောင်စီစဉ်ပေးပါတယ်။ +Views Files တွေက `app/views` directory ထဲမှာ ရှိပါတယ်။ Views မှာ ထုံးစံအတိုင်း သင့် application ရဲ့ HTML တွေပါဝင်ပါတယ် ။ - // For a route with the following URI: profile/{id} +အောက်မှာဖော်ပြထားတာကတော့ Views နမူနာတစ်ခုပါ: - return redirect()->route('profile', ['id' => 1]); + -#### Populating Parameters Via Eloquent Models + + +

    Hello,

    + + -If you are redirecting to a route with an "ID" parameter that is being populated from an Eloquent model, you may simply pass the model itself. The ID will be extracted automatically: +အဲ့ဒီ့အထက်က View ကို browser ကိုအောက်ကလို retun ပြန်ခဲ့ပါတယ် - // For a route with the following URI: profile/{id} + Route::get('/', function() + { + return View::make('greeting', array('name' => 'Taylor')); + }); - return redirect()->route('profile', [$user]); +The second argument passed to `View::make` is an array of data that should be made available to the view. -If you would like to customize the value that is placed in the route parameter, you should override the `getRouteKey` method on your Eloquent model: +#### Data တွေကို View ဆီကို pass လုပ်ခြင်း - /** - * Get the value of the model's route key. - * - * @return mixed - */ - public function getRouteKey() - { - return $this->slug; - } + // Using conventional approach + $view = View::make('greeting')->with('name', 'Steve'); + + // Using Magic Methods + $view = View::make('greeting')->withName('steve'); + +အထက်ကဥပမာမှာ `$name` variable ကို view ကနေပြီးတော့ access လုပ်နိုင်ပါတယ်၊ နောက် `Steve` ကောပေါ့။ + +သင့်အနေနဲ့ data ထဲက array တွေကို `make` method ရဲ့ second partameter မှာ array ဖြစ်တဲ့ data ကို pass လုပ်နိုင်ပါတယ်။ သင်လုပ်ချင်ရင်ပေါ့ - -### Redirecting To Controller Actions + $view = View::make('greetings', $data); -You may also generate redirects to [controller actions](/docs/{{version}}/controllers). To do so, pass the controller and action name to the `action` method. Remember, you do not need to specify the full namespace to the controller since Laravel's `RouteServiceProvider` will automatically set the base controller namespace: +သင့်အနေနဲ့ data နည်းနည်း လေးကို views အားလုံးကို share နိုင်ပါတယ်၊ - return redirect()->action('HomeController@index'); + View::share('name', 'Steve'); -If your controller route requires parameters, you may pass them as the second argument to the `action` method: +#### View တစ်ခုမှ Sub-View တစ်ခုကို pass လုပ်ခြင်း - return redirect()->action( - 'UserController@profile', ['id' => 1] - ); +တစ်ခါတစ်လေသင့်အနေနဲ့ veiw တစ်ခုကနေ တစ်ခုပြောင်းချင်ပါလိမ့်မယ်။ ဥပမာ၊ ဒုတိယ view တစ်ခုကို `app/views/child/view.php` မှာ stored လုပ်ထားတယ်၊ ကျွန်တော်တို့ နောက်ထက် View တစ်ခုကို Pass လုပ်ချင်တယ်ဆိုရင်... like so: - -### Redirecting With Flashed Session Data + $view = View::make('greeting')->nest('child', 'child.view'); -Redirecting to a new URL and [flashing data to the session](/docs/{{version}}/session#flash-data) are usually done at the same time. Typically, this is done after successfully performing an action when you flash a success message to the session. For convenience, you may create a `RedirectResponse` instance and flash data to the session in a single, fluent method chain: + $view = View::make('greeting')->nest('child', 'child.view', $data); - Route::post('user/profile', function () { - // Update the user's profile... +paraent view က sub-view ဆီကနေ render လုပ်နိုင်ပါပြီ- - return redirect('dashboard')->with('status', 'Profile updated!'); + + +

    Hello!

    + + + + + +## View Composers + +View က rendered ဖြစ်တဲ့အချိန်မှာ View composers တွေက callbacks ဒါမှမဟုတ်ရင် class methods တွေကို ခေါ်ခဲ့တယ် ။ သင့် application မှ render လုပ်ပြီးတော့ သင့်ရဲ့ view ကိုအချိန်တိုင်း သေချာပေါက်ပေးရမယ့် data ရှိတဲ့အခါမျိုးဆိုရင် ... အဲ့ဒီ့ code ကို location တစ်ခုထဲကနေ View Composer တစ်ခုက organize လုပ်နိုင်တယ် ။ + +#### View Composer တစ်ခု သတ်မှတ်ခြင်း + + View::composer('profile', function($view) + { + $view->with('count', User::count()); + }); + +အခု `profile` view က rendered ဖြစ်တဲ့အချိန်တိုင်းမှာ `count` data က view ဆီကို bound ပါလိမ့်မယ် + +View composer တစ်ခုကနေ Multiple Views ကိုတစ်ကြိမ်တည်းသင့်အနေနဲ့ attach လုပ်နိုင်ပါတယ် + + View::composer(array('profile','dashboard'), function($view) + { + $view->with('count', User::count()); }); -After the user is redirected, you may display the flashed message from the [session](/docs/{{version}}/session). For example, using [Blade syntax](/docs/{{version}}/blade): +If you would rather use a class based composer, which will provide the benefits of being resolved through the application [IoC Container](ioc.md), you may do so: - @if (session('status')) -
    - {{ session('status') }} -
    - @endif + View::composer('profile', 'ProfileComposer'); - -## Other Response Types +View Composer Class တစ်ခုကို အောက်ကလို define လုပ်နိုင်ပါတယ် : -The `response` helper may be used to generate other types of response instances. When the `response` helper is called without arguments, an implementation of the `Illuminate\Contracts\Routing\ResponseFactory` [contract](/docs/{{version}}/contracts) is returned. This contract provides several helpful methods for generating responses. + class ProfileComposer { - -### View Responses + public function compose($view) + { + $view->with('count', User::count()); + } -If you need control over the response's status and headers but also need to return a [view](/docs/{{version}}/views) as the response's content, you should use the `view` method: + } - return response() - ->view('hello', $data, 200) - ->header('Content-Type', $type); +#### Composer နှစ်ခုသတ်မှတ်ခြင်း -Of course, if you do not need to pass a custom HTTP status code or custom headers, you should use the global `view` helper function. +တစ်ချိန်တည်းမှာဘဲ Composers Group တွေကို Register လုပ်ဖို့သင့်အနေနဲ့ `composers` method ကိုသုံးနိုင်ပါတယ်။ - -### JSON Responses -The `json` method will automatically set the `Content-Type` header to `application/json`, as well as convert the given array to JSON using the `json_encode` PHP function: + View::composers(array( + 'AdminComposer' => array('admin.index', 'admin.profile'), + 'UserComposer' => 'user', + )); - return response()->json([ - 'name' => 'Abigail', - 'state' => 'CA' - ]); +> **Note:** There is no convention on where composer classes may be stored. You are free to store them anywhere as long as they can be autoloaded using the directives in your `composer.json` file. -If you would like to create a JSONP response, you may use the `json` method in combination with the `withCallback` method: +### View Creators ( View ဖန်တီးသူများ) - return response() - ->json(['name' => 'Abigail', 'state' => 'CA']) - ->withCallback($request->input('callback')); +View **creators** တွေက view composers တွေလုပ်သလိုမျိုးတစ်ပုံစံတည်းလုပ်တာပါ။ သို့ပေမယ့်လည်း...view တွေ instantiated ဖြစ်ပြီးပြီဆိုမှ သူတို့က ချက်ချင်း fired လုပ်တာပါ။ View creator တစ်ခုလုပ်ဖို့ Register လုပ်ချင်တယ်ဆိုရင် `creator` method ကိုသုံးပါ။ - -### File Downloads + View::creator('profile', function($view) + { + $view->with('count', User::count()); + }); -The `download` method may be used to generate a response that forces the user's browser to download the file at the given path. The `download` method accepts a file name as the second argument to the method, which will determine the file name that is seen by the user downloading the file. Finally, you may pass an array of HTTP headers as the third argument to the method: + +## Special Responses - return response()->download($pathToFile); +#### JSON Response တစ်ခုပြုလုပ်ခြင်း - return response()->download($pathToFile, $name, $headers); + return Response::json(array('name' => 'Steve', 'state' => 'CA')); -> {note} Symfony HttpFoundation, which manages file downloads, requires the file being downloaded to have an ASCII file name. +#### JSON Response တစ်ခုပြုလုပ်ခြင်း - -### File Responses + return Response::json(array('name' => 'Steve', 'state' => 'CA'))->setCallback(Input::get('callback')); -The `file` method may be used to display a file, such as an image or PDF, directly in the user's browser instead of initiating a download. This method accepts the path to the file as its first argument and an array of headers as its second argument: +#### File Download Response တစ်ခုပြုလုပ်ခြင်း - return response()->file($pathToFile); + return Response::download($pathToFile); - return response()->file($pathToFile, $headers); + return Response::download($pathToFile, $name, $headers); + +> **Note:** Symfony HttpFoundation, which manages file downloads, requires the file being downloaded to have an ASCII file name. ## Response Macros -If you would like to define a custom response that you can re-use in a variety of your routes and controllers, you may use the `macro` method on the `Response` facade. For example, from a [service provider's](/docs/{{version}}/providers) `boot` method: +သင့်အနေနဲ့ကိုယ်ပိုင် response တစ်ခုပြုလုပ်ပြီးတော့ routes နဲ့ controllers တွေကနေပြန်ပြီးတော့အသုံးပြုချင်တယ်ဆိုရင်... သင့်အနေနဲ့ `Response::macro` method ကိုသုံးနိုင်ပါတယ် - caps('foo'); +micros တွေကို သင့်ရဲ့ `app/start` files ထဲမှာ define လုပ်ထားရပါမယ်။ တစ်နည်းအားဖြင့် သင့် separate လုပ်ထားတဲ့ macros တွေကို `start` files မှာသင်ပြန် organize လုပ်ရပါမယ်။ diff --git a/routing.md b/routing.md old mode 100644 new mode 100755 index 9e70e4b..0109ed5 --- a/routing.md +++ b/routing.md @@ -1,266 +1,360 @@ -# Routing - -- [Basic Routing](#basic-routing) -- [Route Parameters](#route-parameters) - - [Required Parameters](#required-parameters) - - [Optional Parameters](#parameters-optional-parameters) -- [Named Routes](#named-routes) -- [Route Groups](#route-groups) - - [Middleware](#route-group-middleware) - - [Namespaces](#route-group-namespaces) - - [Sub-Domain Routing](#route-group-sub-domain-routing) - - [Route Prefixes](#route-group-prefixes) -- [Route Model Binding](#route-model-binding) - - [Implicit Binding](#implicit-binding) - - [Explicit Binding](#explicit-binding) -- [Form Method Spoofing](#form-method-spoofing) -- [Accessing The Current Route](#accessing-the-current-route) +# Route လုပ်ခြင်း + +- [လမ်းကြောင်းပေးခြင်း အခြေခံ](#basic-routing) +- [လမ်းကြောင်းထိန်းကွပ် ကိန်းများ](#route-parameters) +- [Route Filterများ](#route-filters) +- [အမည်ရှိ လမ်းကြောင်းများ](#named-routes) +- [လမ်းကြောင်းအုပ်စုများ](#route-groups) +- [Sub-Domain များ အသုံးပြု ၍ လမ်းကြောင်းပေးခြင်း](#sub-domain-routing) +- [လမ်းကြောင်းရှေ့ ဆွယ်ပေးခြင်း](#route-prefixing) +- [လမ်းကြောင်း နှင့် Model ချိတ်တွယ်ခြင်း](#route-model-binding) +- [404 error များ ထုတ်လွှတ်ခြင်း](#throwing-404-errors) +- [Controller များအား လမ်းကြောင်းပေးခြင်း](#routing-to-controllers) -## Basic Routing -The most basic Laravel routes simply accept a URI and a `Closure`, providing a very simple and expressive method of defining routes: +###လမ်းကြောင်းပေးခြင်း(Routing) အခြေခံ - Route::get('foo', function () { - return 'Hello World'; - }); +သင့် application ၏ လမ်းကြောင်း အများစု ကို `app/routes.php` ဖိုင် တွင် သတ်မှတ်ရပါမည်။ `Laravel` တွင် အရိုးရှင်းဆုံး လမ်းကြောင်းတစ်ခုသည် `URI` တစ်ခု နှင့် `closure` ပြန်ခေါ်ချိတ် method (callback method) တစ်ခု ပါ ၀င် ပါသည်။ +#### အခြေခံ GET လမ်းကြောင်း -#### The Default Route Files + Route::get('/', function() + { + return 'Hello World'; + }); -All Laravel routes are defined in your route files, which are located in the `routes` directory. These files are automatically loaded by the framework. The `routes/web.php` file defines routes that are for your web interface. These routes are assigned the `web` middleware group, which provides features like session state and CSRF protection. The routes in `routes/api.php` are stateless and are assigned the `api` middleware group. +#### အခြေခံ POST လမ်းကြောင်း -For most applications, you will begin by defining routes in your `routes/web.php` file. + Route::post('foo/bar', function() + { + return 'Hello World'; + }); -#### Available Router Methods +#### လမ်းကြောင်းတစ်ခုအား HTTP ကြိယာ အများ ဖြင့် မှတ်ပုံတင်ခြင်း -The router allows you to register routes that respond to any HTTP verb: + Route::match(array('GET', 'POST'), '/', function() + { + return 'Hello World'; + }); - Route::get($uri, $callback); - Route::post($uri, $callback); - Route::put($uri, $callback); - Route::patch($uri, $callback); - Route::delete($uri, $callback); - Route::options($uri, $callback); +#### လမ်းကြောင်းတစ်ခုအား မည်သည့် HTTP ကြိယာဖြင့် ဖြစ်စေ သက်ဆိုင်စေရန် မှတ်ပုံတင်ခြင်း -Sometimes you may need to register a route that responds to multiple HTTP verbs. You may do so using the `match` method. Or, you may even register a route that responds to all HTTP verbs using the `any` method: + Route::any('foo', function() + { + return 'Hello World'; + }); - Route::match(['get', 'post'], '/', function () { - // - }); +#### လမ်းကြောင်းတစ်ခုအား HTTPS ဖြင့် မဖြစ်မနေ အသုံးပြ ုစေချင်း - Route::any('foo', function () { - // - }); + Route::get('foo', array('https', function() + { + return 'Must be over HTTPS'; + })); -#### CSRF Protection +မကြာခဏ သင့် လမ်းကြောင်းများအတွက် `URL` များ ထုတ်ရန် လိုအပ်ပါလိမ့်မည်။ ထို့အတွက် `URL::to` method ဖြင့် အသုံးပြုနိုင်ပါသည်။ -Any HTML forms pointing to `POST`, `PUT`, or `DELETE` routes that are defined in the `web` routes file should include a CSRF token field. Otherwise, the request will be rejected. You can read more about CSRF protection in the [CSRF documentation](/docs/{{version}}/csrf): - -
    - {{ csrf_field() }} - ... -
    + $url = URL::to('foo'); -## Route Parameters +## လမ်းကြောင်းထိန်းကွပ် ကိန်းရှင်များ - -### Required Parameters + Route::get('user/{id}', function($id) + { + return 'User '.$id; + }); -Of course, sometimes you will need to capture segments of the URI within your route. For example, you may need to capture a user's ID from the URL. You may do so by defining route parameters: +#### မထည့်လည်းရသော လမ်းကြောင်းထိန်းကွပ်ကိန်းရှင်များ - Route::get('user/{id}', function ($id) { - return 'User '.$id; - }); + Route::get('user/{name?}', function($name = null) + { + return $name; + }); -You may define as many route parameters as required by your route: +#### ပေးထားသော မူလတန်ဖိုးများဖြင့် လမ်းကြောင်းထိန်းကွပ်ကိန်းရှင်များ - Route::get('posts/{post}/comments/{comment}', function ($postId, $commentId) { - // - }); + Route::get('user/{name?}', function($name = 'John') + { + return $name; + }); -Route parameters are always encased within `{}` braces and should consist of alphabetic characters. Route parameters may not contain a `-` character. Use an underscore (`_`) instead. +#### Regular Expression များဖြင့် လမ်းကြောင်းထိန်းကွပ်ကိန်းများအား ကန့်သတ်ခြင်း - -### Optional Parameters + Route::get('user/{name}', function($name) + { + // + }) + ->where('name', '[A-Za-z]+'); -Occasionally you may need to specify a route parameter, but make the presence of that route parameter optional. You may do so by placing a `?` mark after the parameter name. Make sure to give the route's corresponding variable a default value: + Route::get('user/{id}', function($id) + { + // + }) + ->where('id', '[0-9]+'); - Route::get('user/{name?}', function ($name = null) { - return $name; - }); +#### Where အကန့်အသတ်များအား Array အဖြစ်ဖြင့် ပေးပို့ခြင်း - Route::get('user/{name?}', function ($name = 'John') { - return $name; - }); +အကယ်၍ လို အပ်ပါက ကန့်သတ်ချက်များအား `Array` အဖြစ်တွဲ၍လည်း သုံးနိုင်ပါသည်။ - -## Named Routes + Route::get('user/{id}/{name}', function($id, $name) + { + // + }) + ->where(array('id' => '[0-9]+', 'name' => '[a-z]+')) -Named routes allow the convenient generation of URLs or redirects for specific routes. You may specify a name for a route by chaining the `name` method onto the route definition: +#### Global Pattern များ သတ်မှတ်ခြင်း - Route::get('user/profile', function () { - // - })->name('profile'); +အကယ်၍ လမ်းကြောင်းထိန်းကွပ်တစ်မျိ ုးအား ပေးထားသော regular expression တစ်ခုဖြင့် ကန့်သတ်လိုပါက `pattern` method ကို အသုံးပြ ုနိုင်ပါသည်။ -You may also specify route names for controller actions: + Route::pattern('id', '[0-9]+'); - Route::get('user/profile', 'UserController@showProfile')->name('profile'); + Route::get('user/{id}', function($id) + { + // Only called if {id} is numeric. + }); -#### Generating URLs To Named Routes +#### လမ်းကြောင်းထိန်းကွပ်ကိန်းတစ်ခု၏ တန်ဖိုး ကို အသုံးပြ ုခြင်း -Once you have assigned a name to a given route, you may use the route's name when generating URLs or redirects via the global `route` function: +အကယ်၍ လမ်းကြောင်းထိန်းကွပ် ကိန်းတစ်ခု ၏ တန်ဖိုးအား လမ်းကြောင်း၏ အပြင်ဘက်တွင် အသုံးပြု လိုပါက `Route::input` method ကို အသုံးပြု နိုင်ပါသည်။ - // Generating URLs... - $url = route('profile'); + Route::filter('foo', function() + { + if (Route::input('id') == 1) + { + // + } + }); - // Generating Redirects... - return redirect()->route('profile'); + +## Route filter များ -If the named route defines parameters, you may pass the parameters as the second argument to the `route` function. The given parameters will automatically be inserted into the URL in their correct positions: +route filter များ သည် ပေးထားသော လမ်းကြောင်းတစ်ခုကို အသုံးပြ ုနိုင်စွမ်း ကန့်သတ်ရာ၌ လွယ်ကူသက်သာအောင် ဖန်တီးပေးထားသော နည်းလမ်းတစ်မျိ ုးဖြစ်ပါသည်။ ၎င်းတို့ သည် သင့် site တွင် အသိအမှတ်ပြု စစ်ဆေးချက်များ (Authentications) လို အပ်ပါက အသုံးဝင်နိုင်ပါသည်။ Laravel framework အတွင်း၌ပင် `auth filter`, `auth.basic filter`, `guest filter`, `csrffilter` အစရှိသဖြင့် များစွာသော route filter များ ပါ၀င်ပါသည်။၎င်းတို့ အားလုံး သည် `app/filters.php` ဖိုင်တွင် တည်ရှိပါသည်။ - Route::get('user/{id}/profile', function ($id) { - // - })->name('profile'); +#### Route filter တစ်ခု သတ်မှတ်ခြင်း - $url = route('profile', ['id' => 1]); + Route::filter('old', function() + { + if (Input::get('age') < 200) + { + return Redirect::to('home'); + } + }); - -## Route Groups +အကယ်၍ ပေးထားသော Web Server ၏ တုန့်ပြန်ချက် သည် route filter တစ်ခုဆီမှ ပြန်လာခြင်းဖြစ်ပါက ထို တုန့်ပြန်ချက်အား မူလတောင်းဆိုချက်၏ တုန့်ပြန်ချက်အဖြစ် စဉ်းစားမည်ဖြစ်ပြီး လမ်းကြောင်းကို execute လုပ်မည် မဟုတ်ပါ။ထို့ပြင် သတ်မှတ်ထားပြီးသော နောက်ဆွယ် route filters(after filters)ကို လည်း ပျက်ပြယ်စေမည် ဖြစ်ပါသည်။ -Route groups allow you to share route attributes, such as middleware or namespaces, across a large number of routes without needing to define those attributes on each individual route. Shared attributes are specified in an array format as the first parameter to the `Route::group` method. +#### လမး်ကြောင်းတစ်ခုပေါ်သို့ Route filter တစ်ခု ချိတ်ဆက်ခြင်း - -### Middleware + Route::get('user', array('before' => 'old', function() + { + return 'You are over 200 years old!'; + })); -To assign middleware to all routes within a group, you may use the `middleware` key in the group attribute array. Middleware are executed in the order they are listed in the array: +#### Controller Action တစ်ခု သို့ Route filter တစ်ခု ချိတ်ဆက်ခြင်း - Route::group(['middleware' => 'auth'], function () { - Route::get('/', function () { - // Uses Auth Middleware - }); + Route::get('user', array('before' => 'old', 'uses' => 'UserController@showProfile')); - Route::get('user/profile', function () { - // Uses Auth Middleware - }); - }); +#### လမ်းကြောင်းတစ်ခုပေါ်သို့ Route filter အများ ချိတ်ဆက်ခြင်း - -### Namespaces + Route::get('user', array('before' => 'auth|old', function() + { + return 'You are authenticated and over 200 years old!'; + })); -Another common use-case for route groups is assigning the same PHP namespace to a group of controllers using the `namespace` parameter in the group array: +#### လမ်းကြောင်းတစ်ခုပေါ်သို့ Route filter အများ အား Array အဖြစ်ဖြင့် ချိတ်ဆက်ခြင်း - Route::group(['namespace' => 'Admin'], function() { - // Controllers Within The "App\Http\Controllers\Admin" Namespace - }); + Route::get('user', array('before' => array('auth', 'old'), function() + { + return 'You are authenticated and over 200 years old!'; + })); -Remember, by default, the `RouteServiceProvider` includes your route files within a namespace group, allowing you to register controller routes without specifying the full `App\Http\Controllers` namespace prefix. So, you only need to specify the portion of the namespace that comes after the base `App\Http\Controllers` namespace. +#### Route filter ထိန်းကွပ်ကိန်းများ သတ်မှတ်ခြင်း - -### Sub-Domain Routing + Route::filter('age', function($route, $request, $value) + { + // + }); -Route groups may also be used to handle sub-domain routing. Sub-domains may be assigned route parameters just like route URIs, allowing you to capture a portion of the sub-domain for usage in your route or controller. The sub-domain may be specified using the `domain` key on the group attribute array: + Route::get('user', array('before' => 'age:200', function() + { + return 'Hello World'; + })); - Route::group(['domain' => '{account}.myapp.com'], function () { - Route::get('user/{id}', function ($account, $id) { - // - }); - }); +နောက်ဆွယ် Route filter များ သည် `$response` အား တတိယမြောက် argument အဖြစ် လက်ခံရရှိပါသည်။ - -### Route Prefixes + Route::filter('log', function($route, $request, $response) + { + // + }); -The `prefix` group attribute may be used to prefix each route in the group with a given URI. For example, you may want to prefix all route URIs within the group with `admin`: +#### Pattern အခြေခံ Filter များ - Route::group(['prefix' => 'admin'], function () { - Route::get('users', function () { - // Matches The "/admin/users" URL - }); - }); +Route filter တစ်ခုအား လမ်းကြောင်းတို့၏ URI ပေါ် အခြေခံ ၍ သတ်မှတ်ထားသော လမ်းကြောင်း အုပ်စုတစ်ခု လုံး ပေါ်သို့ သက်ရောက်စေရန်လည်း သတ်မှတ်နိုင်ပါသည်။ - -## Route Model Binding + Route::filter('admin', function() + { + // + }); + + Route::when('admin/*', 'admin'); + +ပေးထားသော ဥပမာတွင် `admin` route filter သည် `admin/` ဖြင့် စသော လမ်းကြောင်းအားလုံး ပေါ်သို့ သက်ရောက်မည် ဖြစ်ပါသည်။ ခရေပွင့် စာလုံး `*` ကို မည်သည့် စာလုံးနှင့်မဆို ကိုက်ညီစေမည့် သံခိတ် စာလုံး အဖြစ် အသုံးပြု နိုင်ပါသည်။ + +ထို့ အပြင် HTTP ကြိယာများဖြင့်လည်း pattern အခြေခံ filter များ အား ကန့်သတ်နိုင်ပါသည်။ +You may also constrain pattern filters by HTTP verbs: + + Route::when('admin/*', 'admin', array('post')); + +#### Filter class များ + +အဆင့်မြင့် route filter များ တွင် Closure တစ်ခု ထက် class တစ်ခုကို အသုံးပြု ချင် ကောင်း အသုံးပြု ပါလိမ့်မည်။စင်စစ် filter class များသည် application [IoC Container](ioc.md) မှ တစ်ဆင့် ပြန်ဖြည်ချင်းဖြစ်ရာ dependency injection ကို အသုံး ပြု နိုင်စေ၍ test လုပ်ခြင်းကို အထောက်အပံ့ကောင်းကောင်းပေးနိုင်ပါသည်။ + +#### Class အခြေခံ filter တစ်ခု အား မှတ်ပုံတင်ခြင်း + + Route::filter('foo', 'FooFilter'); + +ပုံမှန်အားဖြင့် `FooFilter` class ၏ `filter` method ကို ခေါ်ပါလိမ့်မည်။ + + class FooFilter { + + public function filter() + { + // Filter logic... + } + + } + +အကယ်၍ `filter` method ကို မသုံးလိုပါက အခြား method တစ်ခုကို သတ်မှတ်လိုက်ရုံပင်။ + + Route::filter('foo', 'FooFilter@foo'); + + +## အမည်ရှိ လမ်းကြောင်းများ + +အမည်ရှိလမ်းကြောင်းများသည် လမ်းကြောင်းလွှဲများ ပြု လုပ်သောအခါ သို့မဟုတ် URL များ ရေးသားသောအခါ လမ်းကြောင်းများကို ညွှန်းဆိုရာ ၌ ပိုမိုလွယ်ကူစေပါသည်။ + + Route::get('user/profile', array('as' => 'profile', function() + { + // + })); + +Controller action အတွဲများ အတွက် လည်း လမ်းကြောင်းအမည်များ သတ်မှတ်နိုင်ပါသည်။ + + Route::get('user/profile', array('as' => 'profile', 'uses' => 'UserController@showProfile')); -When injecting a model ID to a route or controller action, you will often query to retrieve the model that corresponds to that ID. Laravel route model binding provides a convenient way to automatically inject the model instances directly into your routes. For example, instead of injecting a user's ID, you can inject the entire `User` model instance that matches the given ID. +အထက်ပါအတိုင်းသတ်မှတ်ပြီးပါက ပေးထားသော လမ်းကြောင်းနာမည်ဖြင့် URL များ ထုတ်ရာ၌ ဖြစ်စေ လမ်းကြောင်းလွှဲများ အသုံးပြု ရာ ၌ ဖြစ်စေ သုံးနိုင်ပါပြီ။ - -### Implicit Binding + $url = URL::route('profile'); + + $redirect = Redirect::route('profile'); + +လက်ရှိ ရောက်ရှိနေသော လမ်းကြောင်း၏ အမည်ကို `currentRouteName` method ဖြင့် သိရှိအသုံးပြု နိုင်ပါသည်။ + + $name = Route::currentRouteName(); + + +## လမ်းကြောင်း အုပ်စုများ -Laravel automatically resolves Eloquent models defined in routes or controller actions whose variable names match a route segment name. For example: +တစ်ခါတစ်ရံ လမ်းကြောင်း အုပ်စု တစ်ခု ပေါ်သို့ filter များ သက်ရောက်ဖို့ လိုအပ်ကောင်းလိုအပ်နိုင်ပါသည်။ ထိုအခါမျိ ုးတွင် လမ်းကြောင်းတစ်ခုစီအတွက် filter များသတ်မှတ်မည့်အစား လမ်းကြောင်းအုပ်စု တစ်ခုကို အသုံးပြု နိုင်ပါသည်။ - Route::get('api/users/{user}', function (App\User $user) { - return $user->email; - }); + Route::group(array('before' => 'auth'), function() + { + Route::get('/', function() + { + // Has Auth Filter + }); -In this example, since the Eloquent `$user` variable defined on the route matches the `{user}` segment in the route's URI, Laravel will automatically inject the model instance that has an ID matching the corresponding value from the request URI. If a matching model instance is not found in the database, a 404 HTTP response will automatically be generated. + Route::get('user/profile', function() + { + // Has Auth Filter + }); + }); -#### Customizing The Key Name +`group` array အတွင်းတွင်`namespace` ထိန်းကွပ်ကိန်းထည့်၍ လည်း ပေးထားသော အုပ်စုအတွင်းရှိ controller များအား namespace တစ်ခုအတွင်း ကျရောက်နေစေရန် စီမံနိုင်ပါသည်။ -If you would like implicit model binding to use a database column other than `id` when retrieving a given model class, you may override the `getRouteKeyName` method on the Eloquent model: + Route::group(array('namespace' => 'Admin'), function() + { + // + }); - /** - * Get the route key for the model. - * - * @return string - */ - public function getRouteKeyName() - { - return 'slug'; - } + +## Sub-Domain များ အသုံးပြု ၍ လမ်းကြောင်းပေးခြင်း - -### Explicit Binding +Laravel လမ်းကြောင်းများတွင် သံခိတ်သုံး sub-domain များကို ကောင်းမွန်စွာ စီမံအသုံးချနိုင်ပြီး domain မှ သံခိတ် ထိန်းကွပ်ကိန်းများ ကို ပေးပို့နိုင်ပါသည်။ -To register an explicit binding, use the router's `model` method to specify the class for a given parameter. You should define your explicit model bindings in the `boot` method of the `RouteServiceProvider` class: +#### Sub-domain လမ်းကြောင်းများ မှတ်ပုံတင်ခြင်း - public function boot() - { - parent::boot(); + Route::group(array('domain' => '{account}.myapp.com'), function() + { + + Route::get('user/{id}', function($account, $id) + { + // + }); + + }); + + +## လမ်းကြောင်းရှေ့ ဆွယ်ပေးခြင်း + +လမ်းကြောင်း အုပ်စု တစ်ခု အား `prefix` ထိန်းကွပ်ကိန်းအား `group` array တွင် ထည့်သွင်း၍ ရှေ့ ဆွယ် လမ်းကြောင်းတစ်ခုပေးနိုင်ပါသည်။ + + Route::group(array('prefix' => 'admin'), function() + { + + Route::get('user', function() + { + // + }); + + }); + + +## လမ်းကြောင်း နှင့် Model ချိတ်တွယ်ခြင်း - Route::model('user', 'App\User'); - } +Model ချိတ်တွယ်ခြင်း သည် model instance တစ်ခုအား လမ်းကြောင်းများ အတွင်းသို့ အလွယ်တကူ ထိုးသွင်းနိုင်စေပါသည်။ ဥပမာ user တစ်ယောက်၏ id ကို လမ်းကြောင်းအတွင်း ထည့်သွင်းမည့်အစား ပေးထားသော id နှင့် ကိုက်ညီသည့် user model instance တစ်ခုကို တိုက်ရိုက်ထည့်သွင်းနိုင်ပါသည်။ ပထမဦးစွာ`Route::model` method ကို အသုံးပြု ပြီး ပေးထားသော ထိန်းကွပ်ကိန်းအတွင်း အသုံးပြု မည့် model အမည်ကို သတ်မှတ်ပေးရပါမည်။ -Next, define a route that contains a `{user}` parameter: +#### ထိန်းကွပ်ကိန်းတစ်ခုအား model တစ်ခုဖြင့် ချိတ်တွယ်ခြင်း - $router->get('profile/{user}', function(App\User $user) { - // - }); + Route::model('user', 'User'); -Since we have bound all `{user}` parameters to the `App\User` model, a `User` instance will be injected into the route. So, for example, a request to `profile/1` will inject the `User` instance from the database which has an ID of `1`. +ပြီးနောက် `{user}` ထိန်းကွပ်ကိန်းပါ၀င်သည့် လမ်းကြောင်းတစ်ခု သတ်မှတ်ပေးရပါမည်။ -If a matching model instance is not found in the database, a 404 HTTP response will be automatically generated. + Route::get('profile/{user}', function(User $user) + { + // + }); -#### Customizing The Resolution Logic +`{user}` ထိန်းကွပ်ကိန်းကို `User` model ဖြင့် ချိတ်တွယ်ခဲ့သဖြင့် `User` instance တစ်ခုကို လမ်းကြောင်းအတွင်းသို့ ထိုးသွင်းပါလိမ့်မည်။ ဥပမာအားဖြင့် `profile/1` သို့ လာသော တောင်းဆိုချက်တစ်ခုသည် ID 1 ရှိသော `User` instance တစ်ခုကို ထိုးသွင်းပါလိမ့်မည်။ -If you wish to use your own resolution logic, you may use the `Route::bind` method. The `Closure` you pass to the `bind` method will receive the value of the URI segment and should return the instance of the class that should be injected into the route: +>**မှတ်ချက်** အကယ်၍ ကိုက်ညီသည့် model instance တစ်ခုကို database တွင် ရှာမတွေ့ ပါက 404 error ဖြစ်ပေါ်ပါလိမ့်မည်။ - $router->bind('user', function ($value) { - return App\User::where('name', $value)->first(); - }); +အကယ်၍ မိမိဘာသာ "not found" တုန့်ပြန်ချက်တစ်ခု သတ်မှတ်လိုပါက `model` method တွင် Closure တစ်ခုအား တတိယ arugment အဖြစ် ပေးပို့နိုင်ပါသည်။ - -## Form Method Spoofing + Route::model('user', 'User', function() + { + throw new NotFoundHttpException; + }); -HTML forms do not support `PUT`, `PATCH` or `DELETE` actions. So, when defining `PUT`, `PATCH` or `DELETE` routes that are called from an HTML form, you will need to add a hidden `_method` field to the form. The value sent with the `_method` field will be used as the HTTP request method: +တစ်ခါတစ်ရံ ကိုယ်တိုင် လမ်းကြောင်းထိန်းကွပ်ကိန်းများ မိမိ ဘာသာ ဖြည်လိုခြင်း မျိ ုးရှိနိုင်ပါသည်။ ထို့ အတွက် `Route::bind` method ကို သုံးလိုက်ရုံပင်။ -
    - - -
    + Route::bind('user', function($value, $route) + { + return User::where('name', $value)->first(); + }); -You may use the `method_field` helper to generate the `_method` input: + +## 404 error များ ထုတ်လွှတ်ခြင်း - {{ method_field('PUT') }} +လမ်းကြောင်းတစ်ခု ဆီမှ 404 error တစ်ခု ဖြစ်ပေါ်အောင် ကိုယ်တိုင် ပြု လုပ်နည်း နှစ်မျ ိုး ရှိပါသည်။ ပထမတစ်နည်း မှာ `App::abort` method ကို အသုံးပြု ခြင်းဖြစ်သည်။ - -## Accessing The Current Route + App::abort(404); -You may use the `current`, `currentRouteName`, and `currentRouteAction` methods on the `Route` facade to access information about the route handling the incoming request: +ဒုတိယတည်နည်းမှာ `Symfony\Component\HttpKernel\Exception\NotFoundHttpException` ကို ကိုယ်တိုင် ထုတ်လွှတ်ခြင်းဖြစ်သည်။ - $route = Route::current(); +404 exception များ ကိုင်တွယ်ခြင်း နှင့် ၎င်းတို့ အတွက် ကိုယ်ပိုင်တုန့်ပြန်ချက်များ ပြု လုပ်ခြင်းတို့ နှင့် ပတ်သက်၍ [errors](errors#handling-404-errors.md) အပိုင်းတွင် ပိုမို ဖတ်ရှုနိုင်ပါသည်။ - $name = Route::currentRouteName(); + +## Controller များ အား လမ်းကြောင်းပေးခြင်း - $action = Route::currentRouteAction(); +Laravel တွင် လမ်းကြောင်းပေးရာ၌ Closure များ ကိုသာ မဟုတ် controller class များကို လည်း အသုံးပြု နိုင်သည့် အပြင် [resource controllers](/docs/controllers#resource-controllers လမ်းကြောင်းများ ပါ ခွင့်ပြုထားပါသည်။ -Refer to the API documentation for both the [underlying class of the Route facade](http://laravel.com/api/{{version}}/Illuminate/Routing/Router.html) and [Route instance](http://laravel.com/api/{{version}}/Illuminate/Routing/Route.html) to review all accessible methods. +[Controllers](controllers.md) လမ်းညွှန် တွင်အသေးစိတ် ဖတ်ရှု နိုင်ပါသည်။ diff --git a/scheduling.md b/scheduling.md deleted file mode 100644 index 0d74fa9..0000000 --- a/scheduling.md +++ /dev/null @@ -1,198 +0,0 @@ -# Task Scheduling - -- [Introduction](#introduction) -- [Defining Schedules](#defining-schedules) - - [Schedule Frequency Options](#schedule-frequency-options) - - [Preventing Task Overlaps](#preventing-task-overlaps) -- [Task Output](#task-output) -- [Task Hooks](#task-hooks) - - -## Introduction - -In the past, you may have generated a Cron entry for each task you needed to schedule on your server. However, this can quickly become a pain, because your task schedule is no longer in source control and you must SSH into your server to add additional Cron entries. - -Laravel's command scheduler allows you to fluently and expressively define your command schedule within Laravel itself. When using the scheduler, only a single Cron entry is needed on your server. Your task schedule is defined in the `app/Console/Kernel.php` file's `schedule` method. To help you get started, a simple example is defined within the method. - -### Starting The Scheduler - -When using the scheduler, you only need to add the following Cron entry to your server. If you do not know how to add Cron entries to your server, consider using a service such as [Laravel Forge](https://forge.laravel.com) which can manage the Cron entries for you: - - * * * * * php /path/to/artisan schedule:run >> /dev/null 2>&1 - -This Cron will call the Laravel command scheduler every minute. When the `schedule:run` command is executed, Laravel will evaluate your scheduled tasks and runs the tasks that are due. - - -## Defining Schedules - -You may define all of your scheduled tasks in the `schedule` method of the `App\Console\Kernel` class. To get started, let's look at an example of scheduling a task. In this example, we will schedule a `Closure` to be called every day at midnight. Within the `Closure` we will execute a database query to clear a table: - - call(function () { - DB::table('recent_users')->delete(); - })->daily(); - } - } - -In addition to scheduling `Closure` calls, you may also schedule [Artisan commands](/docs/{{version}}/artisan) and operating system commands. For example, you may use the `command` method to schedule an Artisan command: - - $schedule->command('emails:send --force')->daily(); - -The `exec` command may be used to issue a command to the operating system: - - $schedule->exec('node /home/forge/script.js')->daily(); - - -### Schedule Frequency Options - -Of course, there are a variety of schedules you may assign to your task: - -Method | Description -------------- | ------------- -`->cron('* * * * * *');` | Run the task on a custom Cron schedule -`->everyMinute();` | Run the task every minute -`->everyFiveMinutes();` | Run the task every five minutes -`->everyTenMinutes();` | Run the task every ten minutes -`->everyThirtyMinutes();` | Run the task every thirty minutes -`->hourly();` | Run the task every hour -`->daily();` | Run the task every day at midnight -`->dailyAt('13:00');` | Run the task every day at 13:00 -`->twiceDaily(1, 13);` | Run the task daily at 1:00 & 13:00 -`->weekly();` | Run the task every week -`->monthly();` | Run the task every month -`->monthlyOn(4, '15:00');` | Run the task every month on the 4th at 15:00 -`->quarterly();` | Run the task every quarter -`->yearly();` | Run the task every year -`->timezone('America/New_York');` | Set the timezone - -These methods may be combined with additional constraints to create even more finely tuned schedules that only run on certain days of the week. For example, to schedule a command to run weekly on Monday: - - // Run once per week on Monday at 1 PM... - $schedule->call(function () { - // - })->weekly()->mondays()->at('13:00'); - - // Run hourly from 8 AM to 5 PM on weekdays... - $schedule->command('foo') - ->weekdays() - ->hourly() - ->timezone('America/Chicago') - ->when(function () { - return date('H') >= 8 && date('H') <= 17; - }); - -Below is a list of the additional schedule constraints: - -Method | Description -------------- | ------------- -`->weekdays();` | Limit the task to weekdays -`->sundays();` | Limit the task to Sunday -`->mondays();` | Limit the task to Monday -`->tuesdays();` | Limit the task to Tuesday -`->wednesdays();` | Limit the task to Wednesday -`->thursdays();` | Limit the task to Thursday -`->fridays();` | Limit the task to Friday -`->saturdays();` | Limit the task to Saturday -`->when(Closure);` | Limit the task based on a truth test - -#### Truth Test Constraints - -The `when` method may be used to limit the execution of a task based on the result of a given truth test. In other words, if the given `Closure` returns `true`, the task will execute as long as no other constraining conditions prevent the task from running: - - $schedule->command('emails:send')->daily()->when(function () { - return true; - }); - -The `skip` method may be seen as the inverse of `when`. If the `skip` method returns `true`, the scheduled task will not be executed: - - $schedule->command('emails:send')->daily()->skip(function () { - return true; - }); - -When using chained `when` methods, the scheduled command will only execute if all `when` conditions return `true`. - - -### Preventing Task Overlaps - -By default, scheduled tasks will be run even if the previous instance of the task is still running. To prevent this, you may use the `withoutOverlapping` method: - - $schedule->command('emails:send')->withoutOverlapping(); - -In this example, the `emails:send` [Artisan command](/docs/{{version}}/artisan) will be run every minute if it is not already running. The `withoutOverlapping` method is especially useful if you have tasks that vary drastically in their execution time, preventing you from predicting exactly how long a given task will take. - - -## Task Output - -The Laravel scheduler provides several convenient methods for working with the output generated by scheduled tasks. First, using the `sendOutputTo` method, you may send the output to a file for later inspection: - - $schedule->command('emails:send') - ->daily() - ->sendOutputTo($filePath); - -If you would like to append the output to a given file, you may use the `appendOutputTo` method: - - $schedule->command('emails:send') - ->daily() - ->appendOutputTo($filePath); - -Using the `emailOutputTo` method, you may e-mail the output to an e-mail address of your choice. Note that the output must first be sent to a file using the `sendOutputTo` method. Before e-mailing the output of a task, you should configure Laravel's [e-mail services](/docs/{{version}}/mail): - - $schedule->command('foo') - ->daily() - ->sendOutputTo($filePath) - ->emailOutputTo('foo@example.com'); - -> {note} The `emailOutputTo` and `sendOutputTo` methods are exclusive to the `command` method and are not supported for `call`. - - -## Task Hooks - -Using the `before` and `after` methods, you may specify code to be executed before and after the scheduled task is complete: - - $schedule->command('emails:send') - ->daily() - ->before(function () { - // Task is about to start... - }) - ->after(function () { - // Task is complete... - }); - -#### Pinging URLs - -Using the `pingBefore` and `thenPing` methods, the scheduler can automatically ping a given URL before or after a task is complete. This method is useful for notifying an external service, such as [Laravel Envoyer](https://envoyer.io), that your scheduled task is commencing or has finished execution: - - $schedule->command('emails:send') - ->daily() - ->pingBefore($url) - ->thenPing($url); - -Using either the `pingBefore($url)` or `thenPing($url)` feature requires the Guzzle HTTP library. You can add Guzzle to your project using the Composer package manager: - - composer require guzzlehttp/guzzle diff --git a/schema.md b/schema.md new file mode 100755 index 0000000..4b2b6fb --- /dev/null +++ b/schema.md @@ -0,0 +1,216 @@ +# Schema Builder + +- [Introduction](#introduction) +- [Creating & Dropping Tables](#creating-and-dropping-tables) +- [Adding Columns](#adding-columns) +- [Renaming Columns](#renaming-columns) +- [Dropping Columns](#dropping-columns) +- [Checking Existence](#checking-existence) +- [Adding Indexes](#adding-indexes) +- [Foreign Keys](#foreign-keys) +- [Dropping Indexes](#dropping-indexes) +- [Dropping Timestamps & Soft Deletes](#dropping-timestamps) +- [Storage Engines](#storage-engines) + + +## Introduction + +The Laravel `Schema` class provides a database agnostic way of manipulating tables. It works well with all of the databases supported by Laravel, and has a unified API across all of these systems. + + +## Creating & Dropping Tables + +To create a new database table, the `Schema::create` method is used: + + Schema::create('users', function($table) + { + $table->increments('id'); + }); + +The first argument passed to the `create` method is the name of the table, and the second is a `Closure` which will receive a `Blueprint` object which may be used to define the new table. + +To rename an existing database table, the `rename` method may be used: + + Schema::rename($from, $to); + +To specify which connection the schema operation should take place on, use the `Schema::connection` method: + + Schema::connection('foo')->create('users', function($table) + { + $table->increments('id'); + }); + +To drop a table, you may use the `Schema::drop` method: + + Schema::drop('users'); + + Schema::dropIfExists('users'); + + +## Adding Columns + +To update an existing table, we will use the `Schema::table` method: + + Schema::table('users', function($table) + { + $table->string('email'); + }); + +The table builder contains a variety of column types that you may use when building your tables: + +Command | Description +------------- | ------------- +`$table->bigIncrements('id');` | Incrementing ID using a "big integer" equivalent. +`$table->bigInteger('votes');` | BIGINT equivalent to the table +`$table->binary('data');` | BLOB equivalent to the table +`$table->boolean('confirmed');` | BOOLEAN equivalent to the table +`$table->char('name', 4);` | CHAR equivalent with a length +`$table->date('created_at');` | DATE equivalent to the table +`$table->dateTime('created_at');` | DATETIME equivalent to the table +`$table->decimal('amount', 5, 2);` | DECIMAL equivalent with a precision and scale +`$table->double('column', 15, 8);` | DOUBLE equivalent with precision +`$table->enum('choices', array('foo', 'bar'));` | ENUM equivalent to the table +`$table->float('amount');` | FLOAT equivalent to the table +`$table->increments('id');` | Incrementing ID to the table (primary key). +`$table->integer('votes');` | INTEGER equivalent to the table +`$table->longText('description');` | LONGTEXT equivalent to the table +`$table->mediumInteger('numbers');` | MEDIUMINT equivalent to the table +`$table->mediumText('description');` | MEDIUMTEXT equivalent to the table +`$table->morphs('taggable');` | Adds INTEGER `taggable_id` and STRING `taggable_type` +`$table->nullableTimestamps();` | Same as `timestamps()`, except allows NULLs +`$table->smallInteger('votes');` | SMALLINT equivalent to the table +`$table->tinyInteger('numbers');` | TINYINT equivalent to the table +`$table->softDeletes();` | Adds **deleted\_at** column for soft deletes +`$table->string('email');` | VARCHAR equivalent column +`$table->string('name', 100);` | VARCHAR equivalent with a length +`$table->text('description');` | TEXT equivalent to the table +`$table->time('sunrise');` | TIME equivalent to the table +`$table->timestamp('added_on');` | TIMESTAMP equivalent to the table +`$table->timestamps();` | Adds **created\_at** and **updated\_at** columns +`->nullable()` | Designate that the column allows NULL values +`->default($value)` | Declare a default value for a column +`->unsigned()` | Set INTEGER to UNSIGNED + +#### Using After On MySQL + +If you are using the MySQL database, you may use the `after` method to specify the order of columns: + + $table->string('name')->after('email'); + + +## Renaming Columns + +To rename a column, you may use the `renameColumn` method on the Schema builder. Before renaming a column, be sure to add the `doctrine/dbal` dependency to your `composer.json` file. + + Schema::table('users', function($table) + { + $table->renameColumn('from', 'to'); + }); + +> **Note:** Renaming `enum` column types is not supported. + + +## Dropping Columns + +#### Dropping A Column From A Database Table + + Schema::table('users', function($table) + { + $table->dropColumn('votes'); + }); + +#### Dropping Multiple Columns From A Database Table + + Schema::table('users', function($table) + { + $table->dropColumn('votes', 'avatar', 'location'); + }); + + +## Checking Existence + +#### Checking For Existence Of Table + +You may easily check for the existence of a table or column using the `hasTable` and `hasColumn` methods: + + if (Schema::hasTable('users')) + { + // + } + +#### Checking For Existence Of Columns + + if (Schema::hasColumn('users', 'email')) + { + // + } + + +## Adding Indexes + +The schema builder supports several types of indexes. There are two ways to add them. First, you may fluently define them on a column definition, or you may add them separately: + + $table->string('email')->unique(); + +Or, you may choose to add the indexes on separate lines. Below is a list of all available index types: + +Command | Description +------------- | ------------- +`$table->primary('id');` | Adding a primary key +`$table->primary(array('first', 'last'));` | Adding composite keys +`$table->unique('email');` | Adding a unique index +`$table->index('state');` | Adding a basic index + + +## Foreign Keys + +Laravel also provides support for adding foreign key constraints to your tables: + + $table->foreign('user_id')->references('id')->on('users'); + +In this example, we are stating that the `user_id` column references the `id` column on the `users` table. + +You may also specify options for the "on delete" and "on update" actions of the constraint: + + $table->foreign('user_id') + ->references('id')->on('users') + ->onDelete('cascade'); + +To drop a foreign key, you may use the `dropForeign` method. A similar naming convention is used for foreign keys as is used for other indexes: + + $table->dropForeign('posts_user_id_foreign'); + +> **Note:** When creating a foreign key that references an incrementing integer, remember to always make the foreign key column `unsigned`. + + +## Dropping Indexes + +To drop an index you must specify the index's name. Laravel assigns a reasonable name to the indexes by default. Simply concatenate the table name, the names of the column in the index, and the index type. Here are some examples: + +Command | Description +------------- | ------------- +`$table->dropPrimary('users_id_primary');` | Dropping a primary key from the "users" table +`$table->dropUnique('users_email_unique');` | Dropping a unique index from the "users" table +`$table->dropIndex('geo_state_index');` | Dropping a basic index from the "geo" table + + +## Dropping Timestamps & SoftDeletes + +To drop the `timestamps`, `nullableTimestamps` or `softDeletes` column types, you may use the following methods: + +Command | Description +------------- | ------------- +`$table->dropTimestamps();` | Dropping the **created\_at** and **updated\_at** columns from the table +`$table->dropSoftDeletes();` | Dropping **deleted\_at** column from the table + + +## Storage Engines + +To set the storage engine for a table, set the `engine` property on the schema builder: + + Schema::create('users', function($table) + { + $table->engine = 'InnoDB'; + + $table->string('email'); + }); diff --git a/scout.md b/scout.md deleted file mode 100644 index 9e12c3c..0000000 --- a/scout.md +++ /dev/null @@ -1,263 +0,0 @@ -# Laravel Scout - -- [မိတ်ဆက်](#introduction) -- [Installation](#installation) - - [Queueing](#queueing) - - [Driver Prerequisites](#driver-prerequisites) -- [Configuration](#configuration) - - [Configuring Model Indexes](#configuring-model-indexes) - - [Configuring Searchable Data](#configuring-searchable-data) -- [Indexing](#indexing) - - [Batch Import](#batch-import) - - [Adding Records](#adding-records) - - [Updating Records](#updating-records) - - [Removing Records](#removing-records) - - [Pausing Indexing](#pausing-indexing) -- [Searching](#searching) - - [Where Clauses](#where-clauses) - - [Pagination](#pagination) - - -## မိတ်ဆက် - -[Eloquent models](/docs/{{version}}/eloquent) အတွက် full-text search ကို Laravel Scout ကလွယ်ကူတဲ့ driver based solution အဖြစ်ပြုလုပ်ပေးထားပါတယ်။ Model observers တွေကိုသုံးပြီးတော့ search indexes အဖြစ် Eloquent records တွေနဲ့အလိုအလျောက် sync လုပ်ပေးမှာဖြစ်ပါတယ်။ - -လက်ရှိမှာတော့ Scout ကို [Algolia](https://www.algolia.com/) driver နဲ့ ship လုပ်ပေးမှာဖြစ်ပါတယ်၊ ဒါပေမယ့် custom drivers တွေပြုလုပ်ရတာကလွယ်ကူတော့ Scout ကို extend လုပ်ပြီးတော့ကိုယ်ပိုင် search implementations တွေလည်းပြုလုပ်နိုင်ပါတယ်။ - - -## Installation - -ပထမဆုံး Scout ကို Composer package manager ကနေ install လုပ်လိုက်ပါ - - - composer require laravel/scout - -ပြီးရင်တော့ `ScoutServiceProvider` ကို `config/app.php` array configuration file မှာထည့်လိုက်ပါ - - - Laravel\Scout\ScoutServiceProvider::class, - -Scout service provider ကို register လုပ်ပြီးပြီဆိုရင် Scout configuration ကို `vendor:publish` Artisan command run ပြီးတော့ publish လုပ်လိုက်ပါ။ ဒီ publish command run လိုက်တာနဲ့ `config` directory မှာ `scout.php` configuration file ကို publish လုပ်သွားမှာဖြစ်ပါတယ် - - - php artisan vendor:publish - -နောက်ဆုံးအဆင့်အနေနဲ့ကတော့ `Laravel\Scout\Searchable` trait ကိုကိုယ်ရှာစေချင်တဲ့ Model မှာထည့်ပါ။ အဲ့ဒီ့ trait က model နဲ့ search driver ကြားမှာ sync လုပ်အောင် model observer တစ်ခု register လုပ်ပါလိမ့်မယ်။ - - -### Queueing - -While not strictly required to use Scout, you should strongly consider configuring a [queue driver](/docs/{{version}}/queues) before using the library. Running a queue worker will allow Scout to queue all operations that sync your model information to your search indexes, providing much better response times for your application's web interface. - -Once you have configured a queue driver, set the value of the `queue` option in your `config/scout.php` configuration file to `true`: - - 'queue' => true, - - -### Driver Prerequisites - -#### Algolia - -When using the Algolia driver, you should configure your Algolia `id` and `secret` credentials in your `config/scout.php` configuration file. Once your credentials have been configured, you will also need to install the Algolia PHP SDK via the Composer package manager: - - composer require algolia/algoliasearch-client-php - - -## Configuration - - -### Configuring Model Indexes - -Each Eloquent model is synced with a given search "index", which contains all of the searchable records for that model. In other words, you can think of each index like a MySQL table. By default, each model will be persisted to an index matching the model's typical "table" name. Typically, this is the plural form of the model name; however, you are free to customize the model's index by overriding the `searchableAs` method on the model: - - -### Configuring Searchable Data - -By default, the entire `toArray` form of a given model will be persisted to its search index. If you would like to customize the data that is synchronized to the search index, you may override the `toSearchableArray` method on the model: - - toArray(); - - // Customize array... - - return $array; - } - } - - -## Indexing - - -### Batch Import - -If you are installing Scout into an existing project, you may already have database records you need to import into your search driver. Scout provides an `import` Artisan command that you may use to import all of your existing records into your search indexes: - - php artisan scout:import "App\Post" - - -### Adding Records - -Once you have added the `Laravel\Scout\Searchable` trait to a model, all you need to do is `save` a model instance and it will automatically be added to your search index. If you have configured Scout to [use queues](#queueing) this operation will be performed in the background by your queue worker: - - $order = new App\Order; - - // ... - - $order->save(); - -#### Adding Via Query - -If you would like to add a collection of models to your search index via an Eloquent query, you may chain the `searchable` method onto an Eloquent query. The `searchable` method will [chunk the results](/docs/{{version}}/eloquent#chunking-results) of the query and add the records to your search index. Again, if you have configured Scout to use queues, all of the chunks will be added in the background by your queue workers: - - // Adding via Eloquent query... - App\Order::where('price', '>', 100)->searchable(); - - // You may also add records via relationships... - $user->orders()->searchable(); - - // You may also add records via collections... - $orders->searchable(); - -The `searchable` method can be considered an "upsert" operation. In other words, if the model record is already in your index, it will be updated. If it does not exist in the search index, it will be added to the index. - - -### Updating Records - -To update a searchable model, you only need to update the model instance's properties and `save` the model to your database. Scout will automatically persist the changes to your search index: - - $order = App\Order::find(1); - - // Update the order... - - $order->save(); - -You may also use the `searchable` method on an Eloquent query to update a collection of models. If the models do not exist in your search index, they will be created: - - // Updating via Eloquent query... - App\Order::where('price', '>', 100)->searchable(); - - // You may also update via relationships... - $user->orders()->searchable(); - - // You may also update via collections... - $orders->searchable(); - - -### Removing Records - -To remove a record from your index, simply `delete` the model from the database. This form of removal is even compatible with [soft deleted](/docs/{{version}}/eloquent#soft-deleting) models: - - $order = App\Order::find(1); - - $order->delete(); - -If you do not want to retrieve the model before deleting the record, you may use the `unsearchable` method on an Eloquent query instance or collection: - - // Removing via Eloquent query... - App\Order::where('price', '>', 100)->unsearchable(); - - // You may also remove via relationships... - $user->orders()->unsearchable(); - - // You may also remove via collections... - $orders->unsearchable(); - - -### Pausing Indexing - -Sometimes you may need to perform a batch of Eloquent operations on a model without syncing the model data to your search index. You may do this using the `withoutSyncingToSearch` method. This method accepts a single callback which will be immediately executed. Any model operations that occur within the callback will not be synced to the model's index: - - App\Order::withoutSyncingToSearch(function () { - // Perform model actions... - }); - - -## Searching - -You may begin searching a model using the `search` method. The search method accepts a single string that will be used to search your models. You should then chain the `get` method onto the search query to retrieve the Eloquent models that match the given search query: - - $orders = App\Order::search('Star Trek')->get(); - -Since Scout searches return a collection of Eloquent models, you may even return the results directly from a route or controller and they will automatically be converted to JSON: - - use Illuminate\Http\Request; - - Route::get('/search', function (Request $request) { - return App\Order::search($request->search)->get(); - }); - - -### Where Clauses - -Scout allows you to add simple "where" clauses to your search queries. Currently, these clauses only support basic numeric equality checks, and are primarily useful for scoping search queries by a tenant ID. Since a search index is not a relational database, more advanced "where" clauses are not currently supported: - - $orders = App\Order::search('Star Trek')->where('user_id', 1)->get(); - - -### Pagination - -In addition to retrieving a collection of models, you may paginate your search results using the `paginate` method. This method will return a `Paginator` instance just as if you had [paginated a traditional Eloquent query](/docs/{{version}}/pagination): - - $orders = App\Order::search('Star Trek')->paginate(); - -You may specify how many models to retrieve per page by passing the amount as the first argument to the `paginate` method: - - $orders = App\Order::search('Star Trek')->paginate(15); - -Once you have retrieved the results, you may display the results and render the page links using [Blade](/docs/{{version}}/blade) just as if you had paginated a traditional Eloquent query: - -
    - @foreach ($orders as $order) - {{ $order->price }} - @endforeach -
    - - {{ $orders->links() }} \ No newline at end of file diff --git a/security.md b/security.md new file mode 100755 index 0000000..01e7c15 --- /dev/null +++ b/security.md @@ -0,0 +1,310 @@ +# Security + +- [Configuration](#configuration) +- [Storing Passwords](#storing-passwords) +- [Authenticating Users](#authenticating-users) +- [Manually Logging In Users](#manually) +- [Protecting Routes](#protecting-routes) +- [HTTP Basic Authentication](#http-basic-authentication) +- [Password Reminders & Reset](#password-reminders-and-reset) +- [Encryption](#encryption) +- [Authentication Drivers](#authentication-drivers) + + +## Configuration + +Laravel aims to make implementing authentication very simple. In fact, almost everything is configured for you out of the box. The authentication configuration file is located at `app/config/auth.php`, which contains several well documented options for tweaking the behavior of the authentication facilities. + +By default, Laravel includes a `User` model in your `app/models` directory which may be used with the default Eloquent authentication driver. Please remember when building the Schema for this Model to ensure that the password field is a minimum of 60 characters. + +If your application is not using Eloquent, you may use the `database` authentication driver which uses the Laravel query builder. + +> **Note:** Before getting started, make sure that your `users` (or equivalent) table contains a nullable, string `remember_token` column of 100 characters. This column will be used to store a token for "remember me" sessions being maintained by your application. + + +## Storing Passwords + +The Laravel `Hash` class provides secure Bcrypt hashing: + +#### Hashing A Password Using Bcrypt + + $password = Hash::make('secret'); + +#### Verifying A Password Against A Hash + + if (Hash::check('secret', $hashedPassword)) + { + // The passwords match... + } + +#### Checking If A Password Needs To Be Rehashed + + if (Hash::needsRehash($hashed)) + { + $hashed = Hash::make('secret'); + } + + +## Authenticating Users + +To log a user into your application, you may use the `Auth::attempt` method. + + if (Auth::attempt(array('email' => $email, 'password' => $password))) + { + return Redirect::intended('dashboard'); + } + +Take note that `email` is not a required option, it is merely used for example. You should use whatever column name corresponds to a "username" in your database. The `Redirect::intended` function will redirect the user to the URL they were trying to access before being caught by the authentication filter. A fallback URI may be given to this method in case the intended destination is not available. + +When the `attempt` method is called, the `auth.attempt` [event](events.md) will be fired. If the authentication attempt is successful and the user is logged in, the `auth.login` event will be fired as well. + +#### Determining If A User Is Authenticated + +To determine if the user is already logged into your application, you may use the `check` method: + + if (Auth::check()) + { + // The user is logged in... + } + +#### Authenticating A User And "Remembering" Them + +If you would like to provide "remember me" functionality in your application, you may pass `true` as the second argument to the `attempt` method, which will keep the user authenticated indefinitely (or until they manually logout). Of course, your `users` table must include the string `remember_token` column, which will be used to store the "remember me" token. + + if (Auth::attempt(array('email' => $email, 'password' => $password), true)) + { + // The user is being remembered... + } + +**Note:** If the `attempt` method returns `true`, the user is considered logged into the application. + +#### Determining If User Authed Via Remember +If you are "remembering" user logins, you may use the `viaRemember` method to determine if the user was authenticated using the "remember me" cookie: + + if (Auth::viaRemember()) + { + // + } + +#### Authenticating A User With Conditions + +You also may add extra conditions to the authenticating query: + + if (Auth::attempt(array('email' => $email, 'password' => $password, 'active' => 1))) + { + // The user is active, not suspended, and exists. + } + +> **Note:** For added protection against session fixation, the user's session ID will automatically be regenerated after authenticating. + +#### Accessing The Logged In User + +Once a user is authenticated, you may access the User model / record: + + $email = Auth::user()->email; + +To retrieve the authenticated user's ID, you may use the `id` method: + + $id = Auth::id(); + +To simply log a user into the application by their ID, use the `loginUsingId` method: + + Auth::loginUsingId(1); + +#### Validating User Credentials Without Login + +The `validate` method allows you to validate a user's credentials without actually logging them into the application: + + if (Auth::validate($credentials)) + { + // + } + +#### Logging A User In For A Single Request + +You may also use the `once` method to log a user into the application for a single request. No sessions or cookies will be utilized. + + if (Auth::once($credentials)) + { + // + } + +#### Logging A User Out Of The Application + + Auth::logout(); + + +## Manually Logging In Users + +If you need to log an existing user instance into your application, you may simply call the `login` method with the instance: + + $user = User::find(1); + + Auth::login($user); + +This is equivalent to logging in a user via credentials using the `attempt` method. + + +## Protecting Routes + +Route filters may be used to allow only authenticated users to access a given route. Laravel provides the `auth` filter by default, and it is defined in `app/filters.php`. + +#### Protecting A Route + + Route::get('profile', array('before' => 'auth', function() + { + // Only authenticated users may enter... + })); + +### CSRF Protection + +Laravel provides an easy method of protecting your application from cross-site request forgeries. + +#### Inserting CSRF Token Into Form + + + +#### Validate The Submitted CSRF Token + + Route::post('register', array('before' => 'csrf', function() + { + return 'You gave a valid CSRF token!'; + })); + + +## HTTP Basic Authentication + +HTTP Basic Authentication provides a quick way to authenticate users of your application without setting up a dedicated "login" page. To get started, attach the `auth.basic` filter to your route: + +#### Protecting A Route With HTTP Basic + + Route::get('profile', array('before' => 'auth.basic', function() + { + // Only authenticated users may enter... + })); + +By default, the `basic` filter will use the `email` column on the user record when authenticating. If you wish to use another column you may pass the column name as the first parameter to the `basic` method in your `app/filters.php` file: + + Route::filter('auth.basic', function() + { + return Auth::basic('username'); + }); + +#### Setting Up A Stateless HTTP Basic Filter + +You may also use HTTP Basic Authentication without setting a user identifier cookie in the session, which is particularly useful for API authentication. To do so, define a filter that returns the `onceBasic` method: + + Route::filter('basic.once', function() + { + return Auth::onceBasic(); + }); + +If you are using PHP FastCGI, HTTP Basic authentication will not work correctly by default. The following lines should be added to your `.htaccess` file: + + RewriteCond %{HTTP:Authorization} ^(.+)$ + RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] + + +## Password Reminders & Reset + +### Model & Table + +Most web applications provide a way for users to reset their forgotten passwords. Rather than forcing you to re-implement this on each application, Laravel provides convenient methods for sending password reminders and performing password resets. To get started, verify that your `User` model implements the `Illuminate\Auth\Reminders\RemindableInterface` contract. Of course, the `User` model included with the framework already implements this interface, and uses the `Illuminate\Auth\Reminders\RemindableTrait` to include the methods needed to implement the interface. + +#### Implementing The RemindableInterface + + use Illuminate\Auth\Reminders\RemindableTrait; + use Illuminate\Auth\Reminders\RemindableInterface; + + class User extends Eloquent implements RemindableInterface { + + use RemindableTrait; + + } + +#### Generating The Reminder Table Migration + +Next, a table must be created to store the password reset tokens. To generate a migration for this table, simply execute the `auth:reminders-table` Artisan command: + + php artisan auth:reminders-table + + php artisan migrate + +### Password Reminder Controller + +Now we're ready to generate the password reminder controller. To automatically generate a controller, you may use the `auth:reminders-controller` Artisan command, which will create a `RemindersController.php` file in your `app/controllers` directory. + + php artisan auth:reminders-controller + +The generated controller will already have a `getRemind` method that handles showing your password reminder form. All you need to do is create a `password.remind` [view](responses#views.md). This view should have a basic form with an `email` field. The form should POST to the `RemindersController@postRemind` action. + +A simple form on the `password.remind` view might look like this: + +
    + + +
    + +In addition to `getRemind`, the generated controller will already have a `postRemind` method that handles sending the password reminder e-mails to your users. This method expects the `email` field to be present in the `POST` variables. If the reminder e-mail is successfully sent to the user, a `status` message will be flashed to the session. If the reminder fails, an `error` message will be flashed instead. + +Within the `postRemind` controller method you may modify the message instance before it is sent to the user: + + Password::remind(Input::only('email'), function($message) + { + $message->subject('Password Reminder'); + }); + +Your user will receive an e-mail with a link that points to the `getReset` method of the controller. The password reminder token, which is used to identify a given password reminder attempt, will also be passed to the controller method. The action is already configured to return a `password.reset` view which you should build. The `token` will be passed to the view, and you should place this token in a hidden form field named `token`. In addition to the `token`, your password reset form should contain `email`, `password`, and `password_confirmation` fields. The form should POST to the `RemindersController@postReset` method. + +A simple form on the `password.reset` view might look like this: + +
    + + + + + +
    + +Finally, the `postReset` method is responsible for actually changing the password in storage. In this controller action, the Closure passed to the `Password::reset` method sets the `password` attribute on the `User` and calls the `save` method. Of course, this Closure is assuming your `User` model is an [Eloquent model](eloquent.md); however, you are free to change this Closure as needed to be compatible with your application's database storage system. + +If the password is successfully reset, the user will be redirected to the root of your application. Again, you are free to change this redirect URL. If the password reset fails, the user will be redirect back to the reset form, and an `error` message will be flashed to the session. + +### Password Validation + +By default, the `Password::reset` method will verify that the passwords match and are >= six characters. You may customize these rules using the `Password::validator` method, which accepts a Closure. Within this Closure, you may do any password validation you wish. Note that you are not required to verify that the passwords match, as this will be done automatically by the framework. + + Password::validator(function($credentials) + { + return strlen($credentials['password']) >= 6; + }); + +> **Note:** By default, password reset tokens expire after one hour. You may change this via the `reminder.expire` option of your `app/config/auth.php` file. + + +## Encryption + +Laravel provides facilities for strong AES encryption via the mcrypt PHP extension: + +#### Encrypting A Value + + $encrypted = Crypt::encrypt('secret'); + +> **Note:** Be sure to set a 16, 24, or 32 character random string in the `key` option of the `app/config/app.php` file. Otherwise, encrypted values will not be secure. + +#### Decrypting A Value + + $decrypted = Crypt::decrypt($encryptedValue); + +#### Setting The Cipher & Mode + +You may also set the cipher and mode used by the encrypter: + + Crypt::setMode('ctr'); + + Crypt::setCipher($cipher); + + +## Authentication Drivers + +Laravel offers the `database` and `eloquent` authentication drivers out of the box. For more information about adding additional authentication drivers, check out the [Authentication extension documentation](extending#authentication.md). diff --git a/seeding.md b/seeding.md deleted file mode 100644 index 1ab6800..0000000 --- a/seeding.md +++ /dev/null @@ -1,94 +0,0 @@ -# Database: Seeding - -- [Introduction](#introduction) -- [Writing Seeders](#writing-seeders) - - [Using Model Factories](#using-model-factories) - - [Calling Additional Seeders](#calling-additional-seeders) -- [Running Seeders](#running-seeders) - - -## Introduction - -Laravel includes a simple method of seeding your database with test data using seed classes. All seed classes are stored in the `database/seeds` directory. Seed classes may have any name you wish, but probably should follow some sensible convention, such as `UsersTableSeeder`, etc. By default, a `DatabaseSeeder` class is defined for you. From this class, you may use the `call` method to run other seed classes, allowing you to control the seeding order. - - -## Writing Seeders - -To generate a seeder, execute the `make:seeder` [Artisan command](/docs/{{version}}/artisan). All seeders generated by the framework will be placed in the `database/seeds` directory: - - php artisan make:seeder UsersTableSeeder - -A seeder class only contains one method by default: `run`. This method is called when the `db:seed` [Artisan command](/docs/{{version}}/artisan) is executed. Within the `run` method, you may insert data into your database however you wish. You may use the [query builder](/docs/{{version}}/queries) to manually insert data or you may use [Eloquent model factories](/docs/{{version}}/database-testing#model-factories). - -As an example, let's modify the default `DatabaseSeeder` class and add a database insert statement to the `run` method: - - insert([ - 'name' => str_random(10), - 'email' => str_random(10).'@gmail.com', - 'password' => bcrypt('secret'), - ]); - } - } - - -### Using Model Factories - -Of course, manually specifying the attributes for each model seed is cumbersome. Instead, you can use [model factories](/docs/{{version}}/database-testing#model-factories) to conveniently generate large amounts of database records. First, review the [model factory documentation](/docs/{{version}}/database-testing#model-factories) to learn how to define your factories. Once you have defined your factories, you may use the `factory` helper function to insert records into your database. - -For example, let's create 50 users and attach a relationship to each user: - - /** - * Run the database seeds. - * - * @return void - */ - public function run() - { - factory(App\User::class, 50)->create()->each(function($u) { - $u->posts()->save(factory(App\Post::class)->make()); - }); - } - - -### Calling Additional Seeders - -Within the `DatabaseSeeder` class, you may use the `call` method to execute additional seed classes. Using the `call` method allows you to break up your database seeding into multiple files so that no single seeder class becomes overwhelmingly large. Simply pass the name of the seeder class you wish to run: - - /** - * Run the database seeds. - * - * @return void - */ - public function run() - { - $this->call(UsersTableSeeder::class); - $this->call(PostsTableSeeder::class); - $this->call(CommentsTableSeeder::class); - } - - -## Running Seeders - -Once you have written your seeder classes, you may use the `db:seed` Artisan command to seed your database. By default, the `db:seed` command runs the `DatabaseSeeder` class, which may be used to call other seed classes. However, you may use the `--class` option to specify a specific seeder class to run individually: - - php artisan db:seed - - php artisan db:seed --class=UsersTableSeeder - -You may also seed your database using the `migrate:refresh` command, which will also rollback and re-run all of your migrations. This command is useful for completely re-building your database: - - php artisan migrate:refresh --seed diff --git a/session.md b/session.md old mode 100644 new mode 100755 index 1013cd5..3fd4c83 --- a/session.md +++ b/session.md @@ -1,269 +1,121 @@ -# HTTP Session - -- [Introduction](#introduction) - - [Configuration](#configuration) - - [Driver Prerequisites](#driver-prerequisites) -- [Using The Session](#using-the-session) - - [Retrieving Data](#retrieving-data) - - [Storing Data](#storing-data) - - [Flash Data](#flash-data) - - [Deleting Data](#deleting-data) - - [Regenerating The Session ID](#regenerating-the-session-id) -- [Adding Custom Session Drivers](#adding-custom-session-drivers) - - [Implementing The Driver](#implementing-the-driver) - - [Registering The Driver](#registering-the-driver) - - -## Introduction - -Since HTTP driven applications are stateless, sessions provide a way to store information about the user across multiple requests. Laravel ships with a variety of session backends that are accessed through an expressive, unified API. Support for popular backends such as [Memcached](http://memcached.org), [Redis](http://redis.io), and databases is included out of the box. +# ဆက်ရှင် - -### Configuration - -The session configuration file is stored at `config/session.php`. Be sure to review the options available to you in this file. By default, Laravel is configured to use the `file` session driver, which will work well for many applications. In production applications, you may consider using the `memcached` or `redis` drivers for even faster session performance. - -The session `driver` configuration option defines where session data will be stored for each request. Laravel ships with several great drivers out of the box: - -
    -- `file` - sessions are stored in `storage/framework/sessions`. -- `cookie` - sessions are stored in secure, encrypted cookies. -- `database` - sessions are stored in a relational database. -- `memcached` / `redis` - sessions are stored in one of these fast, cache based stores. -- `array` - sessions are stored in a PHP array and will not be persisted. -
    - -> {tip} The array driver is used during [testing](/docs/{{version}}/testing) and prevents the data stored in the session from being persisted. - - -### Driver Prerequisites - -#### Database - -When using the `database` session driver, you will need to create a table to contain the session items. Below is an example `Schema` declaration for the table: - - Schema::create('sessions', function ($table) { - $table->string('id')->unique(); - $table->integer('user_id')->nullable(); - $table->string('ip_address', 45)->nullable(); - $table->text('user_agent')->nullable(); - $table->text('payload'); - $table->integer('last_activity'); - }); - -You may use the `session:table` Artisan command to generate this migration: - - php artisan session:table - - php artisan migrate - -#### Redis - -Before using Redis sessions with Laravel, you will need to install the `predis/predis` package (~1.0) via Composer. You may configure your Redis connections in the `database` configuration file. In the `session` configuration file, the `database` option may be used to specify which Redis connection is used by the session. - - -## Using The Session - - -### Retrieving Data +- [ပြင်ဆင်ခြင်း](#configuration) +- [Session Usage](#session-usage) +- [Flash Data](#flash-data) +- [Database Sessions](#database-sessions) +- [Session Drivers](#session-drivers) -There are two primary ways of working with session data in Laravel: the global `session` helper and via a `Request` instance. First, let's look at accessing the session via a `Request` instance, which can be type-hinted on a controller method. Remember, controller method dependencies are automatically injected via the Laravel [service container](/docs/{{version}}/container): - - session()->get('key'); - - // - } - } + +## ပြင်ဆင်ခြင်း -When you retrieve a value from the session, you may also pass a default value as the second argument to the `get` method. This default value will be returned if the specified key does not exist in the session. If you pass a `Closure` as the default value to the `get` method and the requested key does not exist, the `Closure` will be executed and its result returned: +HTTP မှာ Stateless protocol ဖြစ်သောကြောင့် request တစ်ခုနှင့်တစ်ခု ကြားထဲတွင် Session ထဲတွင် အချက်အလက်များကို သိမ်းဆည်းကာ ပို ့ဆောင်ရပေသည်။ Laravel တွင် session ကို နည်းလမ်းမျိုးစုံဖြင့် အသုံးပြုနိုင်ရန် API တစ်ခုကို ဖန်တီးကာ စုစည်းထားသည်။ အခြားသော ကျော်ကြားသည့် +[Memcached](http://memcached.org) နှင့် [Redis](http://redis.io), Session အဖြစ်အသုံးပြုနိုင်သည့် နည်းလမ်းများကို ပံ့ပိုးထားသည်။ - $value = $request->session()->get('key', 'default'); +Session နှင့်ပတ်သတ်သည့် အချက်အလက်များကို `app/config/session.php` တွင် လိုအပ်သလို ပြောင်းလဲ ရမည် ဖြစ်သည်။ ပုံမှန်အားဖြင့် application အတော်များများတွင် အဆင်ပြေမည့် `file` session driver ကို အသုံးပြုထားသည်။ - $value = $request->session()->get('key', function() { - return 'default'; - }); +#### Reserved Keys (သီးသန့် key) -#### The Global Session Helper -You may also use the global `session` PHP function to retrieve and store data in the session. When the `session` helper is called with a single, string argument, it will return the value of that session key. When the helper is called with an array of key / value pairs, those values will be stored in the session: +`flash` ဆက်ရှင်ကီးကို Laravel Farmework အတွင်းပိုင်းတွင်သုံးထားပါသည်၊ ထို့ကြောင့် သင့်အနေနဲ့အဲ့ဒီ့ `flash` ဆိုတဲ့အမည်နဲ့ session ထဲကို item တစ်ခုမှ မထည့်သင့်ပါ။ - Route::get('home', function () { - // Retrieve a piece of data from the session... - $value = session('key'); + +## Session Usage - // Specifying a default value... - $value = session('key', 'default'); +#### Storing An Item In The Session - // Store a piece of data in the session... - session(['key' => 'value']); - }); + Session::put('key', 'value'); -> {tip} There is little practical difference between using the session via an HTTP request instance versus using the global `session` helper. Both methods are [testable](/docs/{{version}}/testing) via the `assertSessionHas` method which is available in all of your test cases. +#### Push A Value Onto An Array Session Value -#### Retrieving All Session Data + Session::push('user.teams', 'developers'); -If you would like to retrieve all the data in the session, you may use the `all` method: +#### Retrieving An Item From The Session - $data = $request->session()->all(); + $value = Session::get('key'); -#### Determining If An Item Exists In The Session +#### Retrieving An Item Or Returning A Default Value -To determine if a value is present in the session, you may use the `has` method. The `has` method returns `true` if the value is present and is not `null`: + $value = Session::get('key', 'default'); - if ($request->session()->has('users')) { - // - } + $value = Session::get('key', function() { return 'default'; }); -To determine if a value is present in the session, even if its value is `null`, you may use the `exists` method. The `exists` method returns `true` if the value is present: +#### Session မှ value တစ်ခု ထုတ်ယူကာ ဖယ်ထုတ်ခြင်း - if ($request->session()->exists('users')) { - // - } + $value = Session::pull('key', 'default'); - -### Storing Data +#### Session မှ value များအားလုံး ခေါ်ယူခြင်း -To store data in the session, you will typically use the `put` method or the `session` helper: + $data = Session::all(); - // Via a request instance... - $request->session()->put('key', 'value'); +#### Session မှ item ရှိမရှိ စစ်ဆေးခြင်း - // Via the global helper... - session(['key' => 'value']); + if (Session::has('users')) + { + // + } -#### Pushing To Array Session Values +#### Session မှ item တစ်ခုကို ထုတ်ပယ်ခြင်း -The `push` method may be used to push a new value onto a session value that is an array. For example, if the `user.teams` key contains an array of team names, you may push a new value onto the array like so: + Session::forget('key'); - $request->session()->push('user.teams', 'developers'); +#### Session တစ်ခုလုံး ရှင်းပစ်ခြင်း -#### Retrieving & Deleting An Item + Session::flush(); -The `pull` method will retrieve and delete an item from the session in a single statement: +#### Session ID အသစ်ထုတ်ယူခြင်း - $value = $request->session()->pull('key', 'default'); + Session::regenerate(); -### Flash Data - -Sometimes you may wish to store items in the session only for the next request. You may do so using the `flash` method. Data stored in the session using this method will only be available during the subsequent HTTP request, and then will be deleted. Flash data is primarily useful for short-lived status messages: - - $request->session()->flash('status', 'Task was successful!'); - -If you need to keep your flash data around for several requests, you may use the `reflash` method, which will keep all of the flash data for an additional request. If you only need to keep specific flash data, you may use the `keep` method: - - $request->session()->reflash(); - - $request->session()->keep(['username', 'email']); - - -### Deleting Data - -The `forget` method will remove a piece of data from the session. If you would like to remove all data from the session, you may use the `flush` method: - - $request->session()->forget('key'); - - $request->session()->flush(); +## Flash Data - -### Regenerating The Session ID +တခါတရံ တစ်ချို ့သော data များကို နောက်ထပ် request တစ်ခါစာသာ သိမ်းဆည်းလိုပေမည်။ ထိုသို ့ပြုလုပ်နိုင်ရန် `Session::flash` method ကို အသုံးပြုနိုင်သည်။ -Regenerating the session ID is often done in order to prevent malicious users from exploiting a [session fixation](https://en.wikipedia.org/wiki/Session_fixation) attack on your application. + Session::flash('key', 'value'); -Laravel automatically regenerates the session ID during authentication if you are using the built-in `LoginController`; however, if you need to manually regenerate the session ID, you may use the `regenerate` method. +#### နောက်ထပ် request တစ်ခုစာ သက်တမ်းတိုးခြင်း - $request->session()->regenerate(); + Session::reflash(); - -## Adding Custom Session Drivers +#### နောက်ထပ် request တစ်ခုစာ သက်တမ်းတိုးခြင်း (ရွေးချယ်ထားသော data များသာ) - -#### Implementing The Driver + Session::keep(array('username', 'email')); -Your custom session driver should implement the `SessionHandlerInterface`. This interface contains just a few simple methods we need to implement. A stubbed MongoDB implementation looks something like this: + +## Database Sessions - string('id')->unique(); + $table->text('payload'); + $table->integer('last_activity'); + }); -> {tip} Laravel does not ship with a directory to contain your extensions. You are free to place them anywhere you like. In this example, we have created an `Extensions` directory to house the `MongoHandler`. + +Table ကို အသုံးပြုထားသောကြောင့် `session:table` ဟူသည့် Artisan command ကို အသုံးပြုပြီး migration ပြုလုပ်နိုင်သည်။ -Since the purpose of these methods is not readily understandable, let's quickly cover what each of the methods do: -
    -- The `open` method would typically be used in file based session store systems. Since Laravel ships with a `file` session driver, you will almost never need to put anything in this method. You can leave it as an empty stub. It is simply a fact of poor interface design (which we'll discuss later) that PHP requires us to implement this method. -- The `close` method, like the `open` method, can also usually be disregarded. For most drivers, it is not needed. -- The `read` method should return the string version of the session data associated with the given `$sessionId`. There is no need to do any serialization or other encoding when retrieving or storing session data in your driver, as Laravel will perform the serialization for you. -- The `write` method should write the given `$data` string associated with the `$sessionId` to some persistent storage system, such as MongoDB, Dynamo, etc. Again, you should not perform any serialization - Laravel will have already handled that for you. -- The `destroy` method should remove the data associated with the `$sessionId` from persistent storage. -- The `gc` method should destroy all session data that is older than the given `$lifetime`, which is a UNIX timestamp. For self-expiring systems like Memcached and Redis, this method may be left empty. -
    + php artisan session:table - -#### Registering The Driver + composer dump-autoload -Once your driver has been implemented, you are ready to register it with the framework. To add additional drivers to Laravel's session backend, you may use the `extend` method on the `Session` [facade](/docs/{{version}}/facades). You should call the `extend` method from the `boot` method of a [service provider](/docs/{{version}}/providers). You may do this from the existing `AppServiceProvider` or create an entirely new provider: + php artisan migrate - +## Session Drivers - namespace App\Providers; +session "driver" မှ session data များ မည်သည့်နေရာတွင်း သိမ်းဆည်းမည်ကို သတ်မှတ်ထားသည်။ Laravel အနေဖြင့် အတော်လေးကောင်းမွန်သော driver အမျိုးအစားများကို ပံပိုးထားသည်။ - use App\Extensions\MongoSessionStore; - use Illuminate\Support\Facades\Session; - use Illuminate\Support\ServiceProvider; +- `file` - sessions သည် `app/storage/sessions` တွင် သိမ်းဆည်းထားမည်။ +- `cookie` - sessions သည် encrypted cookies အနေဖြင့် သိမ်းဆည်းထားမည် ဖြစ်သည်။ +- `database` session သည့် application ၏ database ထဲတွင် သိမ်းဆည်းထားမည် ဖြစ်သည်။ +- `memcached` / `redis` တို ့သည် မြန်ဆန်သွက်လက်သည့် cache based session engine များဖြစ်ကြသည်။ +- `array` - sessions သည် PHP array အဖြစ် သိမ်းဆည်းမည်ဖြစ်ပြီး နောက်ထပ် request များအတွက် သိမ်းဆည်းထားနိုင်မည် မဟုတ်ပေ။ - class SessionServiceProvider extends ServiceProvider - { - /** - * Perform post-registration booting of services. - * - * @return void - */ - public function boot() - { - Session::extend('mongo', function($app) { - // Return implementation of SessionHandlerInterface... - return new MongoSessionStore; - }); - } - /** - * Register bindings in the container. - * - * @return void - */ - public function register() - { - // - } - } +> **မှတ်ချက်:** array driver သည် [unit tests](testing.md) အတွက် အသုံးပြုခြင်း ဖြစ်ပြီး တကယ့် session data အတွက် အသုံးပြုခြင်း မဟုတ်ပေ။ -Once the session driver has been registered, you may use the `mongo` driver in your `config/session.php` configuration file. diff --git a/ssh.md b/ssh.md new file mode 100755 index 0000000..c069e12 --- /dev/null +++ b/ssh.md @@ -0,0 +1,263 @@ +# SSH + +- [Configuration](#configuration) +- [Basic Usage](#basic-usage) +- [Tasks](#tasks) +- [SFTP Downloads](#sftp-downloads) +- [SFTP Uploads](#sftp-uploads) +- [Tailing Remote Logs](#tailing-remote-logs) +- [Envoy Task Runner](#envoy-task-runner) + + +## Configuration + +Laravel includes a simple way to SSH into remote servers and run commands, allowing you to easily build Artisan tasks that work on remote servers. The `SSH` facade provides the access point to connecting to your remote servers and running commands. + +The configuration file is located at `app/config/remote.php`, and contains all of the options you need to configure your remote connections. The `connections` array contains a list of your servers keyed by name. Simply populate the credentials in the `connections` array and you will be ready to start running remote tasks. Note that the `SSH` can authenticate using either a password or an SSH key. + +> **Note:** Need to easily run a variety of tasks on your remote server? Check out the [Envoy task runner](#envoy-task-runner)! + + +## Basic Usage + +#### Running Commands On The Default Server + +To run commands on your `default` remote connection, use the `SSH::run` method: + + SSH::run(array( + 'cd /var/www', + 'git pull origin master', + )); + +#### Running Commands On A Specific Connection + +Alternatively, you may run commands on a specific connection using the `into` method: + + SSH::into('staging')->run(array( + 'cd /var/www', + 'git pull origin master', + )); + +#### Catching Output From Commands + +You may catch the "live" output of your remote commands by passing a Closure into the `run` method: + + SSH::run($commands, function($line) + { + echo $line.PHP_EOL; + }); + +## Tasks + + +If you need to define a group of commands that should always be run together, you may use the `define` method to define a `task`: + + SSH::into('staging')->define('deploy', array( + 'cd /var/www', + 'git pull origin master', + 'php artisan migrate', + )); + +Once the task has been defined, you may use the `task` method to run it: + + SSH::into('staging')->task('deploy', function($line) + { + echo $line.PHP_EOL; + }); + + +## SFTP Downloads + +The `SSH` class includes a simple way to download files using the `get` and `getString` methods: + + SSH::into('staging')->get($remotePath, $localPath); + + $contents = SSH::into('staging')->getString($remotePath); + + +## SFTP Uploads + +The `SSH` class also includes a simple way to upload files, or even strings, to the server using the `put` and `putString` methods: + + SSH::into('staging')->put($localFile, $remotePath); + + SSH::into('staging')->putString($remotePath, 'Foo'); + + +## Tailing Remote Logs + +Laravel includes a helpful command for tailing the `laravel.log` files on any of your remote connections. Simply use the `tail` Artisan command and specify the name of the remote connection you would like to tail: + + php artisan tail staging + + php artisan tail staging --path=/path/to/log.file + + +## Envoy Task Runner + +- [Installation](#envoy-installation) +- [Running Tasks](#envoy-running-tasks) +- [Multiple Servers](#envoy-multiple-servers) +- [Parallel Execution](#envoy-parallel-execution) +- [Task Macros](#envoy-task-macros) +- [Notifications](#envoy-notifications) +- [Updating Envoy](#envoy-updating-envoy) + +Laravel Envoy provides a clean, minimal syntax for defining common tasks you run on your remote servers. Using a [Blade](templates#blade-templating.md) style syntax, you can easily setup tasks for deployment, Artisan commands, and more. + +> **Note:** Envoy requires PHP version 5.4 or greater, and only runs on Mac / Linux operating systems. + + +### Installation + +First, install Envoy using the Composer `global` command: + + composer global require "laravel/envoy=~1.0" + +Make sure to place the `~/.composer/vendor/bin` directory in your PATH so the `envoy` executable is found when you run the `envoy` command in your terminal. + +Next, create an `Envoy.blade.php` file in the root of your project. Here's an example to get you started: + + @servers(['web' => '192.168.1.1']) + + @task('foo', ['on' => 'web']) + ls -la + @endtask + +As you can see, an array of `@servers` is defined at the top of the file. You can reference these servers in the `on` option of your task declarations. Within your `@task` declarations you should place the Bash code that will be run on your server when the task is executed. + +The `init` command may be used to easily create a stub Envoy file: + + envoy init user@192.168.1.1 + + +### Running Tasks + +To run a task, use the `run` command of your Envoy installation: + + envoy run foo + +If needed, you may pass variables into the Envoy file using command line switches: + + envoy run deploy --branch=master + +You may use the options via the Blade syntax you are used to: + + @servers(['web' => '192.168.1.1']) + + @task('deploy', ['on' => 'web']) + cd site + git pull origin {{ $branch }} + php artisan migrate + @endtask + +#### Bootstrapping + +You may use the ```@setup``` directive to declare variables and do general PHP work inside the Envoy file: + + @setup + $now = new DateTime(); + + $environment = isset($env) ? $env : "testing"; + @endsetup + +You may also use ```@include``` to include any PHP files: + + @include('vendor/autoload.php'); + + +### Multiple Servers + +You may easily run a task across multiple servers. Simply list the servers in the task declaration: + + @servers(['web-1' => '192.168.1.1', 'web-2' => '192.168.1.2']) + + @task('deploy', ['on' => ['web-1', 'web-2']]) + cd site + git pull origin {{ $branch }} + php artisan migrate + @endtask + +By default, the task will be executed on each server serially. Meaning, the task will finish running on the first server before proceeding to execute on the next server. + + +### Parallel Execution + +If you would like to run a task across multiple servers in parallel, simply add the `parallel` option to your task declaration: + + @servers(['web-1' => '192.168.1.1', 'web-2' => '192.168.1.2']) + + @task('deploy', ['on' => ['web-1', 'web-2'], 'parallel' => true]) + cd site + git pull origin {{ $branch }} + php artisan migrate + @endtask + + +### Task Macros + +Macros allow you to define a set of tasks to be run in sequence using a single command. For instance: + + @servers(['web' => '192.168.1.1']) + + @macro('deploy') + foo + bar + @endmacro + + @task('foo') + echo "HELLO" + @endtask + + @task('bar') + echo "WORLD" + @endtask + +The `deploy` macro can now be run via a single, simple command: + + envoy run deploy + + + +### Notifications + +#### HipChat + +After running a task, you may send a notification to your team's HipChat room using the simple `@hipchat` directive: + + @servers(['web' => '192.168.1.1']) + + @task('foo', ['on' => 'web']) + ls -la + @endtask + + @after + @hipchat('token', 'room', 'Envoy') + @endafter + +You can also specify a custom message to the hipchat room. Any variables declared in ```@setup``` or included with ```@include``` will be available for use in the message: + + @after + @hipchat('token', 'room', 'Envoy', "$task ran on [$environment]") + @endafter + +This is an amazingly simple way to keep your team notified of the tasks being run on the server. + +#### Slack + +The following syntax may be used to send a notification to [Slack](https://slack.com): + + @after + @slack('team', 'token', 'channel') + @endafter + + +### Updating Envoy + +To update Envoy, simply run the `self-update` command: + + envoy self-update + +If your Envoy installation is in `/usr/local/bin`, you may need to use `sudo`: + + sudo envoy self-update diff --git a/structure.md b/structure.md deleted file mode 100644 index 022c598..0000000 --- a/structure.md +++ /dev/null @@ -1,156 +0,0 @@ -# Directory Structure - -- [Introduction](#introduction) -- [The Root Directory](#the-root-directory) - - [The `app` Directory](#the-root-app-directory) - - [The `bootstrap` Directory](#the-bootstrap-directory) - - [The `config` Directory](#the-config-directory) - - [The `database` Directory](#the-database-directory) - - [The `public` Directory](#the-public-directory) - - [The `resources` Directory](#the-resources-directory) - - [The `routes` Directory](#the-routes-directory) - - [The `storage` Directory](#the-storage-directory) - - [The `tests` Directory](#the-tests-directory) - - [The `vendor` Directory](#the-vendor-directory) -- [The App Directory](#the-app-directory) - - [The `Console` Directory](#the-console-directory) - - [The `Events` Directory](#the-events-directory) - - [The `Exceptions` Directory](#the-exceptions-directory) - - [The `Http` Directory](#the-http-directory) - - [The `Jobs` Directory](#the-jobs-directory) - - [The `Listeners` Directory](#the-listeners-directory) - - [The `Mail` Directory](#the-mail-directory) - - [The `Notifications` Directory](#the-notifications-directory) - - [The `Policies` Directory](#the-policies-directory) - - [The `Providers` Directory](#the-providers-directory) - - -## Introduction - -The default Laravel application structure is intended to provide a great starting point for both large and small applications. Of course, you are free to organize your application however you like. Laravel imposes almost no restrictions on where any given class is located - as long as Composer can autoload the class. - -#### Where Is The Models Directory? - -When getting started with Laravel, many developers are confused by the lack of a `models` directory. However, the lack of such a directory is intentional. We find the word "models" ambiguous since it means many different things to many different people. Some developers refer to an application's "model" as the totality of all of its business logic, while others refer to "models" as classes that interact with a relational database. - -For this reason, we choose to place Eloquent models in the `app` directory by default, and allow the developer to place them somewhere else if they choose. - - -## The Root Directory - - -#### The App Directory - -The `app` directory, as you might expect, contains the core code of your application. We'll explore this directory in more detail soon; however, almost all of the classes in your application will be in this directory. - - -#### The Bootstrap Directory - -The `bootstrap` directory contains files that bootstrap the framework and configure autoloading. This directory also houses a `cache` directory which contains framework generated files for performance optimization such as the route and services cache files. - - -#### The Config Directory - -The `config` directory, as the name implies, contains all of your application's configuration files. It's a great idea to read through all of these files and familiarize yourself with all of the options available to you. - - -#### The Database Directory - -The `database` directory contains your database migration and seeds. If you wish, you may also use this directory to hold an SQLite database. - - -#### The Public Directory - -The `public` directory contains the `index.php` file, which is the entry point for all requests entering your application. This directory also houses your assets such as images, JavaScript, and CSS. - - -#### The Resources Directory - -The `resources` directory contains your views as well as your raw, un-compiled assets such as LESS, SASS, or JavaScript. This directory also houses all of your language files. - - -#### The Routes Directory - -The `routes` directory contains all of the route definitions for your application. By default, two route files are included with Laravel: `web.php` and `api.php`. The `web.php` file contains routes that the `RouteServiceProvider` places in the `web` middleware group, which provides session state, CSRF protection, and cookie encryption. If your application does not offer a stateless, RESTful API, all of your routes will most likely be defined in the `web.php` file. - -The `api.php` file contains routes that the `RouteServiceProvider` places in the `api` middleware group, which provides rate limiting. These routes are intended to be stateless, so requests entering the application through these routes are intended to be authenticated via tokens and will not have access to session state. - - -#### The Storage Directory - -The `storage` directory contains your compiled Blade templates, file based sessions, file caches, and other files generated by the framework. This directory is segregated into `app`, `framework`, and `logs` directories. The `app` directory may be used to store any files generated by your application. The `framework` directory is used to store framework generated files and caches. Finally, the `logs` directory contains your application's log files. - -The `storage/app/public` directory may be used to store user-generated files, such as profile avatars, that should be publicly accessible. You should create a symbolic link at `public/storage` which points to this directory. You may create the link using the `php artisan storage:link` command. - - -#### The Tests Directory - -The `tests` directory contains your automated tests. An example [PHPUnit](https://phpunit.de/) is provided out of the box. Each test class should be suffixed with the word `Test`. You may run your tests using the `phpunit` or `php vendor/bin/phpunit` commands. - - -#### The Vendor Directory - -The `vendor` directory contains your [Composer](https://getcomposer.org) dependencies. - - -## The App Directory - -The majority of your application is housed in the `app` directory. By default, this directory is namespaced under `App` and is autoloaded by Composer using the [PSR-4 autoloading standard](http://www.php-fig.org/psr/psr-4/). - -The `app` directory contains a variety of additional directories such as `Console`, `Http`, and `Providers`. Think of the `Console` and `Http` directories as providing an API into the core of your application. The HTTP protocol and CLI are both mechanisms to interact with your application, but do not actually contain application logic. In other words, they are simply two ways of issuing commands to your application. The `Console` directory contains all of your Artisan commands, while the `Http` directory contains your controllers, middleware, and requests. - -A variety of other directories will be generated inside the `app` directory as you use the `make` Artisan commands to generate classes. So, for example, the `app/Jobs` directory will not exist until you execute the `make:job` Artisan command to generate a job class. - -> {tip} Many of the classes in the `app` directory can be generated by Artisan via commands. To review the available commands, run the `php artisan list make` command in your terminal. - - -#### The Console Directory - -The `Console` directory contains all of the custom Artisan commands for your application. These commands may be generate using the `make:command` command. This directory also houses your console kernel, which is where your custom Artisan commands are registered and your [scheduled tasks](/docs/{{version}}/scheduling) are defined. - - -#### The Events Directory - -This directory does not exist by default, but will be created for you by the `event:generate` and `event:make` Artisan commands. The `Events` directory, as you might expect, houses [event classes](/docs/{{version}}/events). Events may be used to alert other parts of your application that a given action has occurred, providing a great deal of flexibility and decoupling. - - -#### The Exceptions Directory - -The `Exceptions` directory contains your application's exception handler and is also a good place to place any exceptions thrown by your application. If you would like to customize how your exceptions are logged or rendered, you should modify the `Handler` class in this directory. - - -#### The Http Directory - -The `Http` directory contains your controllers, middleware, and form requests. Almost all of the logic to handle requests entering your application will be placed in this directory. - - -#### The Jobs Directory - -This directory does not exist by default, but will be created for you if you execute the `make:job` Artisan command. The `Jobs` directory houses the [queueable jobs](/docs/{{version}}/queues) for your application. Jobs may be queued by your application or run synchronously within the current request lifecycle. Jobs that run synchronously during the current request are sometimes referred to as "commands" since they are an implementation of the [command pattern](https://en.wikipedia.org/wiki/Command_pattern). - - -#### The Listeners Directory - -This directory does not exist by default, but will be created for you if you execute the `event:generate` or `make:listener` Artisan commands. The `Listeners` directory contains the classes that handle your [events](/docs/{{version}}/events). Event listeners receive an event instance and perform logic in response to the event being fired. For example, a `UserRegistered` event might be handled by a `SendWelcomeEmail` listener. - - -#### The Mail Directory - -This directory does not exist by default, but will be created for you if you execute the `make:mail` Artisan command. The `Mail` directory contains all of your classes that represent emails sent by your application. Mail objects allow you to encapsulate all of the logic of building an email in a single, simple class that may be sent using the `Mail::send` method. - - -#### The Notifications Directory - -This directory does not exist by default, but will be created for you if you execute the `make:notification` Artisan command. The `Notifications` directory contains all of the "transactional" notifications that are sent by your application, such as simple notifications about events that happen within your application. Laravel's notification features abstracts sending notifications over a variety of drivers such as email, Slack, SMS, or stored in a database. - - -#### The Policies Directory - -This directory does not exist by default, but will be created for you if you execute the `make:policy` Artisan command. The `Policies` directory contains the authorization policy classes for your application. Policies are used to determine if a user can perform a given action against a resource. For more information, check out the [authorization documentation](/docs/{{version}}/authorization). - - -#### The Providers Directory - -The `Providers` directory contains all of the [service providers](/docs/{{version}}/providers) for your application. Service providers bootstrap your application by binding services in the service container, registering events, or performing any other tasks to prepare your application for incoming requests. - -In a fresh Laravel application, this directory will already contain several providers. You are free to add your own providers to this directory as needed. diff --git a/summary.md b/summary.md new file mode 100755 index 0000000..16e836e --- /dev/null +++ b/summary.md @@ -0,0 +1,47 @@ +- [Laravel နိဒါန်း](introduction.md) + - [Laravel မိတ်ဆက်](introduction.md) + - [Laravel အကျဉ်းချုပ်](quick.md) + - [Release Notes](releases.md) + - [Upgrade Guide](upgrade.md) +- [Laravel ကိုစတင်လေ့လာခြင်း (အခြေခံ)](installation.md) + - [Laravel install လုပ်ခြင်း](installation.md) + - [Configuration လုပ်ခြင်း](configuration.md) + - [Laravel ရဲ့ Official Development Homestead အကြောင်း](homestead.md) + - [Request Lifecycle ](lifecycle.md) + - [Route လုပ်ခြင်းအကြောင်း](routing.md) + - [Requests နှင့် Input များအကြောင်း ](requests.md) + - [Views နှင့် Responses များအကြောင်း](responses.md) + - [Controllers များအကြောင်း](controllers.md) + - [Errors နှင့် Logging များအကြောင်း](errors.md) +- [Laravel ကိုလေ့လာခြင်း (အဆင့်မြင့်)](security.md) + - [Authentication](security.md) + - [Billing](billing.md) + - [Cache](cache.md) + - [Core Extension](extending.md) + - [Events](events.md) + - [Facades](facades.md) + - [Forms & HTML](html.md) + - [Helpers](helpers.md) + - [IoC Container](ioc.md) + - [Localization](localization.md) + - [Mail](mail.md) + - [Package Development](packages.md) + - [Pagination](pagination.md) + - [Queues](queues.md) + - [Security](security.md) + - [Session](session.md) + - [SSH](ssh.md) + - [Templates](templates.md) + - [Unit Testing](testing.md) + - [Validation](validation.md) +- [Database](database.md) + - [အခြေခံ အသုံးပြုပုံ](database.md) + - [Query Builder](queries.md) + - [Eloquent ORM](eloquent.md) + - [Schema Builder](schema.md) + - [Migrations & Seeding](migrations.md) + - [Redis](redis.md) +- [Artisan CLI](artisan.md) + - [Overview](artisan.md) + - [Development](commands.md) +- [Contributing](contributing.md) \ No newline at end of file diff --git a/templates.md b/templates.md new file mode 100755 index 0000000..243a75e --- /dev/null +++ b/templates.md @@ -0,0 +1,180 @@ +# Templates + +- [Controller Layouts](#controller-layouts) +- [Blade Templating](#blade-templating) +- [Other Blade Control Structures](#other-blade-control-structures) +- [Extending Blade](#extending-blade) + + +## Controller Layouts + +Laravel မှာအသုံးပြုသော templates ပုံစံများထဲကတစ်ခုကတော့ controller layouts ကနေအသုံးပြုတဲ့ပုံစံဖြစ်ပါတယ်။ `layout` property ကို controller မှာသတ်မှတ်လိုက်တာနဲ့ view ဖိုဒါထဲမှာ ကြိုတင်သတ်မှတ်ပြင်ဆင်ထားတဲ့ view ဖိုင်ကို သင့်အတွက်ယူဆောင်ပေးပါလိမ့်မယ်။ ပြီးရင်တော့ controller ကနေညွှန်ကြားလာတဲ့တဲ့ ညွှန်ကြားချက်တွကို လက်ခံဆောင်ရွက်ပေးမှာဖြစ်ပါတယ်။ + +#### Controller တွင် Layout ကိုသတ်မှတ်ခြင်း + + class UserController extends BaseController { + + /** + * The layout that should be used for responses. + */ + protected $layout = 'layouts.master'; + + /** + * Show the user profile. + */ + public function showProfile() + { + $this->layout->content = View::make('user.profile'); + } + + } + + +## Blade Templating + +Laravel မှာပါတဲ့ template ပုံစံနောက်တစ်ခုဖြစ်တဲ့ Blade ဆိုတာကတော့ ရိုးရှင်းပြီး၊ စွမ်းဆောင်ရည်ပြည့်ဝတဲ့ လုပ်ဆောင်ချက်တွေအများကြီးပါတဲ့ template engine တစ်ခုဖြစ်ပါတယ်။ Blade ရဲ့ပုံစံက ပင်မ _template_ မှာတည်ဆောက်ထားတဲ့ပုံစံကို ထပ်ပွားယူပြီး(_inheritance_) အပြောင်းအလဲလုပ်ချင်တဲ့နေရာတွေထဲကို (_section_) လိုအပ်သလို ပြုပြင်ပြောင်းလဲနိုင်တဲ့ ပုံစံဖြစ်ပါတယ်။ Blade template ကိုအသုံးပြုချင်ရင်တော့ `.blade.php` extension နဲ့အသုံးပြုရမှာပါ။ + +#### Blade ပုံစံသတ်မှတ်ခြင်း + + + + + + @section('sidebar') + This is the master sidebar. + @show + +
    + @yield('content') +
    + + + +#### Blade ပုံစံကို အသုံးပြုခြင်း + + @extends('layouts.master') + + @section('sidebar') + @parent + +

    This is appended to the master sidebar.

    + @stop + + @section('content') +

    This is my body content.

    + @stop + +အပေါ်မှာပြထားတဲ့ဥပမာမှာ ပင်မ template ပုံစံကို `extend` လုပ်ယူပြီး ပင်မ layout ထဲက section နေရာကို ထပ်ထည့်ထားတာကို သတိပြုပါ။ ပင်မ layout ထဲမှာ ကြိုတင်သတ်မှတ်ထားတဲ့ အချက်အလက်တွေကို chile view ထဲမှာ ထပ်သုံးချင်ရင် `@parent` ဆိုတဲ့ ညွှန်ကြားချက်ကိုအသုံးပြုနိုင်ပါတယ်။ Sidebar နဲ့ footer ကဲ့သို့သော အပိုင်းတွေအတွက် လိုအပ်တဲ့ အချက်အလက်တွေကို ထပ်ထည့်နိုင်တဲ့ လုပ်ဆောင်ချက်တစ်ခုဖြစ်ပါတယ်။ + +တစ်ခါတစ်ရံ `@section` သတ်မှတ်ထား / မထား မသေချာဘူး `@yield` နဲ့ဆွဲယူထားတဲ့ နေရာထဲကိုလဲ default value တစ်ခု ထည့်ချင်တယ်ဆိုရင် ဒုတိယ argument အနေနဲ့ ထည့်ပေးလိုက်ရင် ရပါတယ်။ + + @yield('section', 'Default Content'); + + +## Blade တွင်အသုံးပြုနိုင်သော အခြား control structures များ + +#### အချက်အလက်ထုတ်ပြခြင်း + + Hello, {{{ $name }}}. + + The current UNIX timestamp is {{{ time() }}}. + +#### အချက်အလက် ရှိ/မရှိ စစ်ဆေးပြီးမှ ထုတ်ပြခြင်း + +တစ်ခါတစ်ရံမှာ အချက်အလက်တစ်ခုကိုထုတ်ပြချင်သော်လည်း အဲ့ဒီ အချက်အလက်ထည့်ထားတဲ့ variable ကို အသုံးပြုထားခြင်း ရှိ/မရှိ မသေချာတဲ့ အခြေအနေမျိုးမှာ ပုံမှန်ဆိုရင် အောက်ပါအတိုင်း အသုံးပြုကြပါတယ်။ + + {{{ isset($name) ? $name : 'Default' }}} + +အဲ့ဒီပုံစံကို Blade နဲ့လွယ်လွယ်ကူကူပဲရေးနိုင်ပါတယ်... အောက်မှာရေးထားတဲ့ပုံစံကိုကြည့်လိုက်ပါ။ + + {{{ $name or 'Default' }}} + +#### တွန့်ကွင်း (Curly Braces) နှင့်အုပ်ထားသော စာသားများအတိုင်း ထုတ်ပြခြင်း + +တွန့်ကွင်း (curly braces) အုပ်ထားတဲ့ စာသားများကို ထုတ်ပြဖို့ လိုအပ်လျှင်တော့ blade ပုံစံကို ရှေ့မှာ `@` သင်္ကေတ နဲ့ခံပြီး အသုံးပြုနိုင်ပါတယ်။ + + @{{ This will not be processed by Blade }} + +အသုံးပြုသူဆီက ဝင်လာမဲ့ အချက်အလက်တွေကို escape သို့မဟုတ် purified လုပ်သင့်ပါတယ်။ အဲ့လိုပြုလုပ်ဖို့အတွက် တွန့်ကွင်းသုံးခု (triple curly brace) ကိုအသုံးပြုနိုင်ပါတယ်။ + + Hello, {{{ $name }}}. + +အကယ်၍ escape မလုပ်ချင်ဘူးဆိုရင်တော့ တွန့်ကွင်း နှစ်ခု (double curly braces) ကိုအသုံးပြုနိုင်ပါတယ်။ + + Hello, {{ $name }}. + +> **သတိပြုရန်:** Application ကိုအသုံးပြုုသူဆီကလာမဲ့ အချက်အလက်တွေကိုထုတ်ပြတဲ့ကိစ္စကို အထူးဂရုစိုက်ဖို့ လိုအပ်ပါတယ်။ အဲ့ဒါကြောင့် HTML entities တွေကို escape ပြုလုပ်ဖို့အတွက် တွန့်ကွင်းသုံးခု (triple curly brace) ကိုအမြဲတမ်းအသုံးပြုသင့်ပါတယ်။ + +#### If Statements + + @if (count($records) === 1) + I have one record! + @elseif (count($records) > 1) + I have multiple records! + @else + I don't have any records! + @endif + + @unless (Auth::check()) + You are not signed in. + @endunless + +#### Loops + + @for ($i = 0; $i < 10; $i++) + The current value is {{ $i }} + @endfor + + @foreach ($users as $user) +

    This is user {{ $user->id }}

    + @endforeach + + @while (true) +

    I'm looping forever.

    + @endwhile + +#### Including Sub-Views + + @include('view.name') + +Include လုပ်ထားတဲ့ view တွေဆီကိုလဲ အချက်အလက်တွေကို passing လုပ်လို့ရပါတယ်။ + + @include('view.name', array('some'=>'data')) + +#### Overwriting Sections + +ပုံမှန်ဆိုရင် sections ဟာ ယခင်ရှိပီးသား အချက်အလက်တွေနဲ့အတူ နောက်ထပ် ထပ်ထည့်လာတဲ့ အချက်အလက်တွေကို ပေါင်းထည့်လိုက်တာဖြစ်ပါတယ်။ အကယ်၍ ယခင်အချက်အလက်တွေကို ဖျက်ပြစ်ပီး နောက်ထပ် ထပ်ထည့်လိုက်တဲ့ အချက်အလက်ကိုပဲ အသုံးပြုချင်ရင်တော့ `overwrite` ကိုအသုံးပြုနိုင်ပါတယ်။ + + @extends('list.item.container') + + @section('list.item.content') +

    This is an item of type {{ $item->type }}

    + @overwrite + +#### Displaying Language Lines + + @lang('language.line') + + @choice('language.line', 1); + +#### Comments + + {{-- This comment will not be in the rendered HTML --}} + + +## Extending Blade + +Blade ကိုအသုံးပြုပြီး စိတ်ကြိုက် control structure တွေကိုပြုလုပ်နိုင်ပါတယ်။ blade file ကို compile လုပ်ပီးတဲ့အခါ၊ သတ်မှတ်ထားတဲ့ စိတ်ကြိုက် control structure တွေကို view အတွက် အချက်အလက်တွေနဲ့အတူ ခေါ်ယူသုံးစွဲပါတယ်။ ရိုးရှင်းလွယ်ကူတဲ့ `str_replace` လိုကိစ္စတွေတင်မက ပိုပြီးရှုပ်ထွေးတဲ့ ကိစ္စတွေအထိ ကိုင်တွယ်ဖြေရှင်းနိုင်ပါတယ်။ + +Blade compiler မှာ `createMatcher` နဲ့ `create:lainMatcher` ဆိုပြီး helper methods နှစ်ခု ရှိပါတယ်။ အဲ့ဒီ methods တွေကနေ စိတ်ကြိုက် control structure တွေပြုလုပ်ဖို့ လိုအပ်တဲ့ အရာတွေကိုပြုလုပ်ပေးပါတယ်။ + +`createPlainMatcher` method ကို `@endif` တို့ `@stop` တို့လို arguments တွေမပါတာအတွက် အသုံးပြုပြီး၊ `createMatcher` method ကိုတော့ arguments ပါတာတွေပြုလုပ်ဖို့အတွက် အသုံးပြုပါတယ်။ + +အောက်ပါ ဥပမာကတော့ `@datatime($var)` ကို ပြုလုပ်ထားတာပါ။ အဲ့ဒီ directive မှာပါတဲ့ `$var` ရဲ့ တန်ဖိုးကို `->format()` အသုံးပြုပြီး အလွယ်တကူ ခေါ်သုံးနိုင်ပါတယ်။ + + Blade::extend(function($view, $compiler) + { + $pattern = $compiler->createMatcher('datetime'); + + return preg_replace($pattern, '$1format('m/d/Y H:i'); ?>', $view); + }); diff --git a/testing.md b/testing.md old mode 100644 new mode 100755 index 9d7141b..27d631e --- a/testing.md +++ b/testing.md @@ -1,49 +1,222 @@ -# Testing +# Unit Testing - [Introduction](#introduction) -- [Environment](#environment) -- [Creating & Running Tests](#creating-and-running-tests) +- [Defining & Running Tests](#defining-and-running-tests) +- [Test Environment](#test-environment) +- [Calling Routes From Tests](#calling-routes-from-tests) +- [Mocking Facades](#mocking-facades) +- [Framework Assertions](#framework-assertions) +- [Helper Methods](#helper-methods) +- [Refreshing The Application](#refreshing-the-application) ## Introduction -Laravel is built with testing in mind. In fact, support for testing with PHPUnit is included out of the box and a `phpunit.xml` file is already setup for your application. The framework also ships with convenient helper methods that allow you to expressively test your applications. +Laravel ဟာ unit testing ကို အဓိကအခြေခံထားပြီး တည်ဆောက်ထားတာ ဖြစ်ပါတယ်။ ဒါ့အပြင် testing framework ဖြစ်တဲ့ PHPUnit support လည်း ပါဝင်ပါတဲ့အတွက် application ကို စ setup လုပ်ကတည်းက `phpunit.xml` ဖိုင်ကို တစ်ခါတည်း setup လုပ်ပေးထားမှာ ဖြစ်ပါတယ်။ PHPUnit အပြင် Laravel မှာ Symfony ရဲ့ HttpKernel, DomCrawler နှင့် BrowserKit တို့ ပါဝင်တဲ့အတွက် testing လုပ်ရာမှာ application ရဲ့ views တွေကို web browser တစ်ခုကဲ့သို့ simulate လုပ်နိုင်ပြီး စစ်ဆေးပြုပြင်နိုင်မှာဖြစ်ပါတယ်။ -An `ExampleTest.php` file is provided in the `tests` directory. After installing a new Laravel application, simply run `phpunit` on the command line to run your tests. +ဥပမာ အနေဖြင့် test ဖိုင်တစ်ခုလည်း `app/tests` folder ထဲမှာပါဝင်ပါတယ်။ Laravel appilcation တစ်ခုကို install လုပ်ပြီးပါက `phpunit` command ကို run ယုံဖြင့် application ရဲ့ tests များကို run နိုင်မှာဖြစ်ပါတယ်။ - -## Environment -When running tests, Laravel will automatically set the configuration environment to `testing`. Laravel automatically configures the session and cache to the `array` driver while testing, meaning no session or cache data will be persisted while testing. + +## Defining & Running Tests (Tests များ သတ်မှတ်ခြင်းနှင့် Run ခြင်း) -You are free to define other testing environment configuration values as necessary. The `testing` environment variables may be configured in the `phpunit.xml` file, but make sure to clear your configuration cache using the `config:clear` Artisan command before running your tests! +Test case ကိုဖန်တီးဖို့ `app/tests` folder ထဲမှာ file အသစ်တစ်ခု ပြုလုပ်ပါ။ class ကတော့ `TestCase` class ကို extend ရမှာဖြစ်ပါတယ်။ ထို့နောက်မှာတော့ သင်နှစ်သက်သလို test methods များကို PHPUnit ကိုအသုံးပြုပြီး ဖန်တီးနိုင်ပြီ ဖြစ်ပါတယ်။ - -## Creating & Running Tests -To create a new test case, use the `make:test` Artisan command: +#### Test Class ဥပမာ - php artisan make:test UserTest + class FooTest extends TestCase { -This command will place a new `UserTest` class within your `tests` directory. You may then define test methods as you normally would using PHPUnit. To run your tests, simply execute the `phpunit` command from your terminal: + public function testSomethingIsTrue() + { + $this->assertTrue(true); + } - **သတိ:** ကိုယ့်ဟာကို `setUp` method ရေးထားပါက `parent::setUp` ကို ခေါ်ဖို့ သတိရပါ။ + + +## Test Environment + +unit tests များကို run နေစဉ် Laravel က configuration environment ကို `testing` သို့ အလိုအလျောက် ပြောင်းထားမှာဖြစ်ပါတယ်။ ထို့အပြင် Laravel ရဲ့ test environment ထဲမှာ `session` နှင့် `cache` တို့ရဲ့ configuration files များပါ ပါဝင်မှာဖြစ်ပါတယ်။ ဒီ drivers နှစ်ခုစလုံးကို test environment ထဲမှာ `array` အဖြစ် set ထားမှာဖြစ်ပါတဲ့အတွက် testing လုပ်ပြီးရင်တော့ testing နဲ့ပတ်သက်တဲ့ session သို့မဟုတ် cache data တွေတော့ ပျက်သွားမှာဖြစ်ပါတယ်။ လိုအပ်ရင်လိုအပ်သလို တခြား testing environments တွေကို ဆက်လက်ဖန်တီးလို့လည်း ရပါတယ်။ + + + +## Calling Routes From Tests (Tests များမှ Routes ကိုခေါ်ခြင်း) + +#### Test တစ်ခုမှ Route ကိုခေါ်ခြင်း +`call` method ကိုအသုံးပြု၍ route တစ်ခုခုကို test ကနေ အလွယ်တကူ ခေါ်နိုင်ပါတယ်၊ + + $response = $this->call('GET', 'user/profile'); + + $response = $this->call($method, $uri, $parameters, $files, $server, $content); + +ထို့နောက် `Illuminate\Http\Response` object ကို စစ်ဆေးနိုင်ပါတယ်။ + + $this->assertEquals('Hello World', $response->getContent()); + +#### Test တစ်ခုမှ Controller ကိုခေါ်ခြင်း + +test ကနေ controller ကိုလည်းခေါ်နိုင်ပါတယ်။ + + $response = $this->action('GET', 'HomeController@index'); + + $response = $this->action('GET', 'UserController@profile', array('user' => 1)); + +ဒီ `getContent` method ဟာ response ကနေ evaluated string contents တွေကို ပြန်ပေးမှာဖြစ်ပါတယ်။ သင့်၏ route မှ `View` return ရင်တော့ `original` property ကို အသုံးပြု၍ access လုပ်နိုင်ပါတယ်၊ + + $view = $response->original; + + $this->assertEquals('John', $view['name']); + +HTTPS route တစ်ခုကိုခေါ်လိုပါက `callSecure` method ကို အသုံးပြုနိုင်ပါတယ်။ + + $response = $this->callSecure('GET', 'foo/bar'); + +> **သတိ:** testing environment တွေထဲမှာ route filters တွေကို disable ထားပါတယ်။. ပြန်လည် enable ချင်ရင်တော့, test ထဲမှာ `Route::enableFilters()` ထည့်လိုက်ပါ။ + +### DOM Crawler + +Route ကိုခေါ်၍ DOM Crawler ကိုလက်ခံပြီး ရလာတဲ့ content ကိုစစ်ဆေးနိုင်ပါတယ်။ + + $crawler = $this->client->request('GET', '/'); + + $this->assertTrue($this->client->getResponse()->isOk()); + + $this->assertCount(1, $crawler->filter('h1:contains("Hello World!")')); + +Crawler အသုံးပြုပုံနှင့်ပတ်သက်ပြီး ပိုသိလိုပါက ၎င်းရဲ့[official documentation](http://symfony.com/doc/master/components/dom_crawler.html) ကို ကိုးကားပါ၊ + + +## Mocking Facades (Facades များ အတုပြုလုပ်ခြင်း) + +Testing လုပ်နေစဉ် ရံဖန်ရံခါမှ Laravel ၏ static facade call တွေကို အတုပြုလုပ် (mock) လိုတတ်ပါတယ်။ ဥပမာအနေဖြင့် အောက်ပါ controller action ကိုကြည့်ပါ။ + + public function getIndex() + { + Event::fire('foo', array('name' => 'Dayle')); + + return 'All done!'; + } + +`Event` class သို့ ခေါ်ထားသော call အား facade မှာရှိတဲ့ `shouldReceive` method ဖြင့် အတုပြုလုပ်နိုင်ပါတယ်။ [Mockery](https://github.com/padraic/mockery) mock instance တစ်ခု ပြန်လည် return မှာ ဖြစ်ပါတယ်။ + +#### Facade တစ်ခု အတုပြုလုပ်ခြင်း + + public function testGetIndex() + { + Event::shouldReceive('fire')->once()->with('foo', array('name' => 'Dayle')); + + $this->call('GET', '/'); + } + +> **သတိ:** `Request` facade ကိုတော့ မ mock သင့်ပါဘူး။ အဲဒီအစား pass ချင်တဲ့ input အား `call` method သို့ pass ပြီး test ကို run ပါ။ + + +## Framework Assertions (Framework စစ်ဆေးခြင်းများ) + +Laravel တွင် testing လုပ်ဖို့ အနည်းငယ် ပိုမိုလွယ်ကူသက်သာစေရန် `assert` methods များပါဝင်ပါတယ်။ + +#### Respones များ HTTP status OK ဖြစ်ကြောင်း စစ်ဆေးခြင်း + + public function testMethod() + { + $this->call('GET', '/'); + + $this->assertResponseOk(); + } + +#### အခြား response statuses များအား စစ်ဆေးခြင်း + + $this->assertResponseStatus(403); + +#### responses များ HTTP Redirects များ ဖြစ်ကြောင်း စစ်ဆေးခြင်း + + $this->assertRedirectedTo('foo'); + + $this->assertRedirectedToRoute('route.name'); + + $this->assertRedirectedToAction('Controller@method'); + +#### View တွင် data ရှိကြောင်း စစ်ဆေးခြင်း + + public function testMethod() + { + $this->call('GET', '/'); + + $this->assertViewHas('name'); + $this->assertViewHas('age', $value); + } + +#### Session တွင် data ရှိကြောင်း စစ်ဆေးခြင်း + + public function testMethod() + { + $this->call('GET', '/'); + + $this->assertSessionHas('name'); + $this->assertSessionHas('age', $value); + } + +#### Session တွင် Errors များ စစ်ဆေးခြင်း + + public function testMethod() { - /** - * A basic test example. - * - * @return void - */ - public function testExample() - { - $this->assertTrue(true); - } + $this->call('GET', '/'); + + $this->assertSessionHasErrors(); + + // Asserting the session has errors for a given key... + $this->assertSessionHasErrors('name'); + + // Asserting the session has errors for several keys... + $this->assertSessionHasErrors(array('name', 'age')); } -> {note} If you define your own `setUp` method within a test class, be sure to call `parent::setUp`. +#### Input အဟောင်းများ Data စစ်ဆေးခြင်း + + public function testMethod() + { + $this->call('GET', '/'); + + $this->assertHasOldInput(); + } + + +## Helper Methods (အထောက်အကူ Methods များ) + +Application test လုပ်ရာတွင် ပိုမိုလွယ်ကူစေရန် `TestCase` class တွင် helper methods များပါဝင်ပါတယ်။ + +#### Tests မှ Sessisons data များ ဖန်တီ ခြင်း flush ခြင်း + + $this->session(['foo' => 'bar']); + + $this->flushSession(); + +#### လက်ရှိ authenticated ဖြစ်ပြီးသော User တစ်ယောက်ဖန်တီးခြင်း + +`be` method အား အသုံးပြု၍ လက်ရှိ authenticated ဖြစ်ပြီးသော user တစ်ယောက်ဖန်တီးနိုင်ပါတယ်။ + + $user = new User(array('name' => 'John')); + + $this->be($user); + +Database အား `seed` method အသုံးပြု၍ re-seed ပြုလုပ်နိုင်ပါတယ်။ + +#### Test မှ Database အား Re-seed ပြုလုပ်ခြင်း + + $this->seed(); + + $this->seed($connection); + +Database seeds များပြုလုပ်ခြင်းနှင့် ပတ်သက်၍ documentation ရဲ့ [migrations and seeding](migrations#database-seeding.md) အခန်းမှာ သွားကြည့်နိုင်ပါတယ်။ + + + +## Application အား refresh ပြုလုပ်ခြင်း + +သင်၏ Laravel `Application/IoC Container` အား `$this->app` မှတစ်ဆင့် မည်သည့် test method မှမဆို access နိုင်ပါတယ်။ ဒီ Application instance ဟာ test case တစ်ခုစီ အတွက် ပြန်လည် refresh သွားမှာဖြစ်ပါတယ်။ Application အား သင် သတ်မှတ်ထားသော method တစ်ခုအတွက်သာ refresh ပြုလုပ်ချင်ပါက test method မှ `refreshApplication` method ကို အသုံးပြုနိုင်ပါတယ်။ ဒါဟာ test cases များ စ run ကတည်းက IoC container ထဲမှာရှိတေသာ အပို bindings များ၊ အတုပြုလုပ်ခြင်း (mocks) များအား reset ပြုလုပ်သွားမှာ ဖြစ်ပါတယ်။ \ No newline at end of file diff --git a/upgrade.md b/upgrade.md old mode 100644 new mode 100755 index 28300a1..6f93156 --- a/upgrade.md +++ b/upgrade.md @@ -1,1100 +1,10 @@ # Upgrade Guide -- [Upgrading To 5.3.0 From 5.2](#upgrade-5.3.0) -- [Upgrading To 5.2.0 From 5.1](#upgrade-5.2.0) -- [Upgrading To 5.1.11](#upgrade-5.1.11) -- [Upgrading To 5.1.0](#upgrade-5.1.0) -- [Upgrading To 5.0.16](#upgrade-5.0.16) -- [Upgrading To 5.0 From 4.2](#upgrade-5.0) - [Upgrading To 4.2 From 4.1](#upgrade-4.2) - [Upgrading To 4.1.29 From <= 4.1.x](#upgrade-4.1.29) - [Upgrading To 4.1.26 From <= 4.1.25](#upgrade-4.1.26) - [Upgrading To 4.1 From 4.0](#upgrade-4.1) - -## Upgrading To 5.3.0 From 5.2 - -#### Estimated Upgrade Time: 2-3 Hours - -> {note} We attempt to document every possible breaking change. Since some of these breaking changes are in obscure parts of the framework only a portion of these changes may actually affect your application. - -### PHP & HHVM - -Laravel 5.3 requires PHP 5.6.4 or higher. HHVM is no longer officially supported as it does not contain the same language features as PHP 5.6+. - -### Deprecations - -All of the deprecations listed in the [Laravel 5.2 upgrade guide](#5.2-deprecations) have been removed from the framework. You should review this list to verify you are no longer using these deprecated features. - -### Arrays - -#### Key / Value Order Change - -The `first`, `last`, and `contains` methods on the `Arr` class now pass the "value" as the first parameter to the given callback Closure. For example: - - Arr::first(function ($value, $key) { - return ! is_null($value); - }); - -In previous versions of Laravel, the `$key` was passed first. Since most use cases are only interested in the `$value` it is now passed first. You should do a "global find" in your application for these methods to verify that you are expecting the `$value` to be passed as the first argument to your Closure. - -### Artisan - -##### The `make:console` Command - -The `make:console` command has been renamed to `make:command`. - -### Authentication - -#### Authentication Scaffolding - -The two default authentication controllers provided with the framework have been split into four smaller controllers. This change provides cleaner, more focused authentication controllers by default. The easiest way to upgrade your application to the new authentication controllers is to [grab a fresh copy of each controller from GitHub](https://github.com/laravel/laravel/tree/master/app/Http/Controllers/Auth) and place them into your application. - -You should also make sure that you are calling the `Route::auth()` method in your `routes.php` file. This method will register the proper routes for the new authentication controllers. - -Once these controllers have been placed into your application, you may need to re-implement any customizations you made to these controllers. For example, if you are customizing the authentication guard that is used for authentication, you may need to override the controller's `guard` method. You can examine each authentication controller's trait to determine which methods to override. - -> {tip} If you were not customizing the authentication controllers, you should just be able to drop in fresh copies of the controllers from GitHub and verify that you are calling the `Route::auth` method in your `routes.php` file. - -#### Password Reset Emails - -Password reset emails now use the new Laravel notifications feature. If you would like to customize the notification sent when sending password reset links, you should override the `sendPasswordResetNotification` method of the `Illuminate\Auth\Passwords\CanResetPassword` trait. - -Your `User` model **must** use the new `Illuminate\Notifications\Notifiable` trait in order for password reset link emails to be delivered: - - {note} Don't forget to register the `Illuminate\Notifications\NotificationServiceProvider` in the `providers` array of your `config/app.php` configuration file. - -#### POST To Logout - -The `Route::auth` method now registers a `POST` route for `/logout` instead of a `GET` route. This prevents other web applications from logging your users out of your application. To upgrade, you should either convert your logout requests to use the `POST` verb or register your own `GET` route for the `/logout` URI: - - Route::get('/logout', 'Auth\LoginController@logout'); - -### Authorization - -#### Calling Policy Methods With Class Names - -Some policy methods only receive the currently authenticated user and not an instance of the model they authorize. This situation is most common when authorizing `create` actions. For example, if you are creating a blog, you may wish to check if a user is authorized to create any posts at all. - -When defining policy methods that will not receive a model instance, such as a `create` method, the class name will no longer be passed as the second argument to the method. Your method should just expect the authenticated user instance: - - /** - * Determine if the given user can create posts. - * - * @param \App\User $user - * @return bool - */ - public function create(User $user) - { - // - } - -#### The `AuthorizesResources` Trait - -The `AuthorizesResources` trait has been merged with the `AuthorizesRequests` trait. You should remove the `AuthorizesResources` trait from your `app/Http/Controllers/Controller.php` file. - -### Blade - -#### Custom Directives - -In prior versions of Laravel, when registering custom Blade directives using the `directive` method, the `$expression` passed to your directive callback contained the outer-most parenthesis. In Laravel 5.3, these outer-most parenthesis are not included in the expression passed to your directive callback. Be sure to review the [Blade extension](/docs/5.3/blade#extending-blade) documentation and verify your custom Blade directives are still working properly. - -### Broadcasting - -#### Service Provider - -Laravel 5.3 includes significant improvements to [event broadcasting](/docs/{{version}}/broadcasting). You should add the new `BroadcastServiceProvider` to your `app/Providers` directory by [grabbing a fresh copy of the source from GitHub](https://raw.githubusercontent.com/laravel/laravel/develop/app/Providers/BroadcastServiceProvider.php). Once you have defined the new service provider, you should add it to the `providers` array of your `config/app.php` configuration file. - -### Cache - -#### Extension Closure Binding & `$this` - -When calling the `Cache::extend` method with a Closure, `$this` will be bound to the `CacheManager` instance, allowing you to call its methods from within your extension Closure: - - Cache::extend('memcached', function ($app, $config) { - try { - return $this->createMemcachedDriver($config); - } catch (Exception $e) { - return $this->createNullDriver($config); - } - }); - -### Collections - -#### Key / Value Order Change - -The `first`, `last`, and `contains` collection methods all pass the "value" as the first parameter to their given callback Closure. For example: - - $collection->first(function ($value, $key) { - return ! is_null($value); - }); - -In previous versions of Laravel, the `$key` was passed first. Since most use cases are only interested in the `$value` it is now passed first. You should do a "global find" in your application for these methods to verify that you are expecting the `$value` to be passed as the first argument to your Closure. - -#### `where` Comparison Now "Loose" By Default - -The `where` method now performs a "loose" comparison by default instead of a strict comparison. If you would like to perform a strict comparison, you may use the `whereStrict` method. - -The `where` method also no longer accepts a third parameter to indicate "strictness". You should explicit call either `where` or `whereStrict` depending on your application's needs. - -### Database - -#### Collections - -The [fluent query builder](/docs/{{version}}/queries) now returns `Illuminate\Support\Collection` instances instead of plain arrays. This brings consistency to the result types returned by the fluent query builder and Eloquent. - -If you do not want to migrate your query builder results to `Collection` instances, you may chain the `all` method onto your calls to the query builder's `get` method. This will return a plain PHP array of the results, allowing you to maintain backwards compatibility: - - $users = DB::table('users')->get()->all(); - -#### Eloquent `$morphClass` Property - -The `$morphClass` property that could be defined on Eloquent models has been removed in favor of defining a "morph map". Defining a morph map provides support for eager loading and resolves additional bugs with polymorphic relations. If you were previously relying on the `$morphClass` property, you should migrate to `morphMap` using the following syntax: - -```php -Relation::morphMap([ - 'YourCustomMorphName' => YourModel::class, -]); -``` - -For example, if you previously defined the following `$morphClass`: - -```php -class User extends Model -{ - protected $morphClass = 'user' -} -``` - -You should define the following `morphMap` in the `boot` method of your `AppServiceProvider`: - -```php -use Illuminate\Database\Eloquent\Relation; - -Relation::morphMap([ - 'user' => User::class, -]); -``` - -#### Eloquent `save` Method - -The Eloquent `save` method now returns `false` if the model has not been changed since the last time it was retrieved or saved. - -#### Eloquent Scopes - -Eloquent scopes now respect the leading boolean of scope constraints. For example, if you are starting your scope with an `orWhere` constraint it will no longer be converted to normal `where`. If you were relying on this feature (e.g. adding multiple `orWhere` constraints within a loop), you should verify that the first condition is a normal `where` to avoid any boolean logic issues. - -If your scopes begin with `where` constraints no action is required. Remember, you can verify your query SQL using the `toSql` method of a query: - - User::where('foo', 'bar')->toSql(); - -#### Join Clause - -The `JoinClause` class has been rewritten to unify its syntax with the query builder. The optional `$where` parameter of the `on` clause has been removed. To add a "where" conditions you should explicitly use one of the `where` methods offered by the [query builder](/docs/{{version}}/queries#where-clauses): - - $query->join('table', function($join) { - $join->on('foo', 'bar')->where('bar', 'baz'); - }); - -The `$bindings` property was also removed. To manipulate join bindings directly you may use the `addBinding` method: - - $query->join(DB::raw('('.$subquery->toSql().') table'), function($join) use ($subquery) { - $join->addBinding($subquery->getBindings(), 'join'); - }); - -### Encryption - -#### Mcrypt Encrypter Has Been Removed - -The Mcrypt encrypter was deprecated during the Laravel 5.1.0 release in June 2015. This encrypter has been totally removed in the 5.3.0 release in favor of the newer encryption implementation based on OpenSSL, which has been the default encryption scheme for all releases since Laravel 5.1.0. - -If you are still using an Mcrypt based `cipher` in your `config/app.php` configuration file, you should update the cipher to `AES-256-CBC` and set your key to a random 32 byte string which may be securely generated using `php artisan key:generate`. - -If you are storing encrypted data in your database using the Mcrypt encrypter, you may install the `laravel/legacy-encrypter` [package](https://github.com/laravel/legacy-encrypter) which includes the legacy Mcrypt encrypter implementation. You should use this package to decrypt your encrypted data and re-encrypt it using the new OpenSSL encrypter. For example, you may do something like the following in a [custom Artisan command](/docs/{{version}}/artisan): - - $legacy = new McryptEncrypter($encryptionKey); - - foreach ($records as $record) { - $record->encrypted = encrypt( - $legacy->decrypt($record->encrypted) - ); - - $record->save(); - } - -### Exception Handler - -#### Constructor - -The base exception handler class now requires a `Illuminate\Container\Container` instance to be passed to its constructor. This change will only affect your application if you have defined a custom `__construct` method in your `app/Exception/Handler.php` file. If you have done this, you should pass a container instance into the `parent::__construct` method: - - parent::__construct(app()); - -### Middleware - -#### `can` Middleware Namespace Change - -The `can` middleware listed in the `$routeMiddleware` property of your HTTP kernel should be updated to the following class: - - 'can' => \Illuminate\Auth\Middleware\Authorize::class, - -#### `can` Middleware Authentication Exception - -The `can` middleware will now throw an instance of `Illuminate\Auth\AuthenticationException` if the user is not authenticated. If you were manually catching a different exception type, you should update your application to catch this exception. In most cases, this change will not affect your application. - -#### Binding Substitution Middleware - -Route model binding is now accomplished using middleware. All applications should add the `Illuminate\Routing\Middleware\SubstituteBindings` to your `web` middleware group in your `app/Http/Kernel.php` file: - - \Illuminate\Routing\Middleware\SubstituteBindings::class, - -You should also register a route middleware for binding substitution in the `$routeMiddleware` property of your HTTP kernel: - - 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, - -Once this route middleware has been registered, you should add it to the `api` middleware group: - - 'api' => [ - 'throttle:60,1', - 'bindings', - ], - -### Notifications - -#### Installation - -Laravel 5.3 includes a new, driver based notification system. You should register the `Illuminate\Notifications\NotificationServiceProvider` in the `providers` array of your `config/app.php` configuration file. - -You should also add the `Illuminate\Support\Facades\Notification` facade to the `aliases` array of your `config/app.php` configuration file. - -Finally, you may use the `Illuminate\Notifications\Notifiable` trait on your `User` model or any other model you wish to receive notifications. - -### Pagination - -#### Customization - -Customizing the paginator's generated HTML is much easier in Laravel 5.3 compared to previous Laravel 5.x releases. Instead of defining a "Presenter" class, you only need to define a simple Blade template. The easiest way to customize the pagination views is by exporting them to your `resources/views/vendor` directory using the `vendor:publish` command: - - php artisan vendor:publish --tag=laravel-pagination - -This command will place the views in the `resources/views/vendor/pagination` directory. The `default.blade.php` file within this directory corresponds to the default pagination view. Simply edit this file to modify the pagination HTML. - -Be sure to review the full [pagination documentation](/docs/{{version}}/pagination) for more information. - -### Queue - -#### Configuration - -In your queue configuration, all `expire` configuration items should be renamed to `retry_after`. Likewise, the Beanstalk configuration's `ttr` item should be renamed to `retry_after`. This name change provides more clarity on the purpose of this configuration option. - -#### Closures - -Queueing closures is no longer supported. If you are queueing a Closure in your application, you should convert the Closure to a class and queue an instance of the class instead. - -#### Collection Serialization - -The `Illuminate\Queue\SerializesModels` trait now properly serializes instances of `Illuminate\Database\Eloquent\Collection`. This will most likely not be a breaking change for the vast majority of applications; however, if your application is absolutely dependent on collections not being re-retrieved from the database by queued jobs, you should verify that this change does not negatively affect your application. - -#### Daemon Workers - -It is no longer necessary to specify the `--daemon` option when calling the `queue:work` Artisan command. Running the `php artisan queue:work` command will automatically assume that you want to run the worker in daemon mode. If you would like to process a single job, you may use the `--once` option on the command: - - // Start a daemon queue worker... - php artisan queue:work - - // Process a single job... - php artisan queue:work --once - -#### Event Data Changes - -Various queue job events such as `JobProcessing` and `JobProcessed` no longer contain the `$data` property. You should update your application to call `$event->job->payload()` to get the equivalent data. - -#### Failed Jobs Table - -If your application has a `failed_jobs` table, you should add a `exception` column to the table. The `exception` column should be a `TEXT` type column and will be used to store a string representation of the exception that caused the job to fail. - -#### Serializing Models On Legacy Style Queue Jobs - -Typically, jobs in Laravel are queued by passing a new job instance to the `Queue::push` method. However, some applications may be queuing jobs using the following legacy syntax: - - Queue::push('ClassName@method'); - -If you are queueing jobs using this syntax, Eloquent models will no longer be automatically serialized and re-retrieved by the queue. If you would like your Eloquent models to be automatically serialized by the queue, you should use the `Illuminate\Queue\SerializesModels` trait on your job class and queue the job using the new `push` syntax: - - Queue::push(new ClassName); - -### Routing - -#### Resource Parameters Are Singular By Default - -In previous versions of Laravel, route parameters registered using `Route::resource` were not "singularized". This could lead to some unexpected behavior when registering route model bindings. For example, given the following `Route::resource` call: - - Route::resource('photos', 'PhotoController'); - -The URI for the `show` route would be defined as follows: - - /photos/{photos} - -In Laravel 5.3, all resource route parameters are singularized by default. So, the same call to `Route::resource` would register the following URI: - - /photos/{photo} - -If you would like to maintain the previous behavior instead of automatically singularizing resource route parameters, you may make the following call to the `singularResourceParameters` method in your `AppServiceProvider`: - - use Illuminate\Support\Facades\Route; - - Route::singularResourceParameters(false); - -#### Resource Route Names No Longer Affected By Prefixes - -URL prefixes no longer affect the route names assigned to routes when using `Route::resource`, since this behavior defeated the entire purpose of using route names in the first place. - -If your application is using `Route::resource` within a `Route::group` call that specified a `prefix` option, you should examine all of your calls to the `route` helper and verify that you are no longer appending the URI `prefix` to the route name. - -If this change causes you to have two routes with the same name, you may use the `names` option when calling `Route::resource` to specify a custom name for a given route. Refer to the [resource routing documentation](/docs/5.3/controllers#resource-controllers) for more information. - -### Validation - -#### Form Request Exceptions - -If a form request's validation fails, Laravel will now throw an instance of `Illuminate\Validation\ValidationException` instead of an instance of `HttpException`. If you are manually catching the `HttpException` instance thrown by a form request, you should update your `catch` blocks to catch the `ValidationException` instead. - -#### Nullable Primitives - -When validating arrays, booleans, integers, numerics, and strings, `null` will no longer be considered a valid value unless the rule set contains the new `nullable` rule: - - Validate::make($request->all(), [ - 'string' => 'nullable|max:5', - ]); - - -## Upgrading To 5.2.0 From 5.1 - -#### Estimated Upgrade Time: Less Than 1 Hour - -> {note} We attempt to provide a very comprehensive listing of every possible breaking change made to the framework. However, many of these changes may not apply to your own application. - -### Updating Dependencies - -Update your `composer.json` file to point to `laravel/framework 5.2.*`. - -Add `"symfony/dom-crawler": "~3.0"` and `"symfony/css-selector": "~3.0"` to the `require-dev` section of your `composer.json` file. - -### Authentication - -#### Configuration File - -You should update your `config/auth.php` configuration file with the following: [https://github.com/laravel/laravel/blob/master/config/auth.php](https://github.com/laravel/laravel/blob/master/config/auth.php) - -Once you have updated the file with a fresh copy, set your authentication configuration options to their desired value based on your old configuration file. If you were using the typical, Eloquent based authentication services available in Laravel 5.1, most values should remain the same. - -Take special note of the `passwords.users.email` configuration option in the new `auth.php` configuration file and verify that the view path matches the actual view path for your application, as the default path to this view was changed in Laravel 5.2. If the default value in the new configuration file does not match your existing view, update the configuration option. - -#### Contracts - -If you are implementing the `Illuminate\Contracts\Auth\Authenticatable` contract but are **not** using the `Authenticatable` trait, you should add a new `getAuthIdentifierName` method to your contract implementation. Typically, this method will return the column name of the "primary key" of your authenticatable entity. For example: `id`. - -This is unlikely to affect your application unless you were manually implementing this interface. - -#### Custom Drivers - -If you are using the `Auth::extend` method to define a custom method of retrieving users, you should now use `Auth::provider` to define your custom user provider. Once you have defined the custom provider, you may configure it in the `providers` array of your new `auth.php` configuration file. - -For more information on custom authentication providers, consult the [full authentication documentation](/docs/{{version}}/authentication). - -#### Redirection - -The `loginPath()` method has been removed from `Illuminate\Foundation\Auth\AuthenticatesUsers`, so placing a `$loginPath` variable in your `AuthController` is no longer required. By default, the trait will always redirect users back to their previous location on authentication errors. - -### Authorization - -The `Illuminate\Auth\Access\UnauthorizedException` has been renamed to `Illuminate\Auth\Access\AuthorizationException`. This is unlikely to affect your application if you are not manually catching this exception. - -### Collections - -#### Eloquent Base Collections - -The Eloquent collection instance now returns a base Collection (`Illuminate\Support\Collection`) for the following methods: `pluck`, `keys`, `zip`, `collapse`, `flatten`, `flip`. - -#### Key Preservation - -The `slice`, `chunk`, and `reverse` methods now preserve keys on the collection. If you do not want these methods to preserve keys, use the `values` method on the `Collection` instance. - -### Composer Class - -The `Illuminate\Foundation\Composer` class has been moved to `Illuminate\Support\Composer`. This is unlikely to affect your application if you were not manually using this class. - -### Commands And Handlers - -#### Self-Handling Commands - -You no longer need to implement the `SelfHandling` contract on your jobs / commands. All jobs are now self-handling by default, so you can remove this interface from your classes. - -#### Separate Commands & Handlers - -The Laravel 5.2 command bus now only supports self-handling commands and no longer supports separate commands and handlers. - -If you would like to continue using separate commands and handlers, you may install a Laravel Collective package which provides backwards-compatible support for this: [https://github.com/LaravelCollective/bus](https://github.com/laravelcollective/bus) - -### Configuration - -#### Environment Value - -Add an `env` configuration option to your `app.php` configuration file that looks like the following: - - 'env' => env('APP_ENV', 'production'), - -#### Caching And Env - -If you are using the `config:cache` command during deployment, you **must** make sure that you are only calling the `env` function from within your configuration files, and not from anywhere else in your application. - -If you are calling `env` from within your application, it is strongly recommended you add proper configuration values to your configuration files and call `env` from that location instead, allowing you to convert your `env` calls to `config` calls. - -#### Compiled Classes - -If present, remove the following lines from `config/compile.php` in the `files` array: - - realpath(__DIR__.'/../app/Providers/BusServiceProvider.php'), - realpath(__DIR__.'/../app/Providers/ConfigServiceProvider.php'), - -Not doing so can trigger an error when running `php artisan optimize` if the service providers listed here do not exist. - -### CSRF Verification - -CSRF verification is no longer automatically performed when running unit tests. This is unlikely to affect your application. - -### Database - -#### MySQL Dates - -Starting with MySQL 5.7, `0000-00-00 00:00:00` is no longer considered a valid date, since `strict` mode is enabled by default. All timestamp columns should receive a valid default value when you insert records into your database. You may use the `useCurrent` method in your migrations to default the timestamp columns to the current timestamps, or you may make the timestamps `nullable` to allow `null` values: - - $table->timestamp('foo')->nullable(); - - $table->timestamp('foo')->useCurrent(); - - $table->nullableTimestamps(); - -#### MySQL JSON Column Type - -The `json` column type now creates actual JSON columns when used by the MySQL driver. If you are not running MySQL 5.7 or above, this column type will not be available to you. Instead, use the `text` column type in your migration. - -#### Seeding - -When running database seeds, all Eloquent models are now unguarded by default. Previously a call to `Model::unguard()` was required. You can call `Model::reguard()` at the top of your `DatabaseSeeder` class if you would like models to be guarded during seeding. - -### Eloquent - -#### Date Casts - -Any attributes that have been added to your `$casts` property as `date` or `datetime` will now be converted to a string when `toArray` is called on the model or collection of models. This makes the date casting conversion consistent with dates specified in your `$dates` array. - -#### Global Scopes - -The global scopes implementation has been re-written to be much easier to use. Your global scopes no longer need a `remove` method, so it may be removed from any global scopes you have written. - -If you were calling `getQuery` on an Eloquent query builder to access the underlying query builder instance, you should now call `toBase`. - -If you were calling the `remove` method directly for any reason, you should change this call to `$eloquentBuilder->withoutGlobalScope($scope)`. - -New methods `withoutGlobalScope` and `withoutGlobalScopes` have been added to the Eloquent query builder. Any calls to `$model->removeGlobalScopes($builder)` may be changed to simply `$builder->withoutGlobalScopes()`. - -#### Primary keys - -By default, Eloquent assumes your primary keys are integers and will automatically cast them to integers. For any primary key that is not an integer you should override the `$incrementing` property on your Eloquent model to `false`: - - /** - * Indicates if the IDs are auto-incrementing. - * - * @var bool - */ - public $incrementing = true; - -### Events - -#### Core Event Objects - -Some of the core events fired by Laravel now use event objects instead of string event names and dynamic parameters. Below is a list of the old event names and their new object based counterparts: - -Old | New -------------- | ------------- -`artisan.start` | `Illuminate\Console\Events\ArtisanStarting` -`auth.attempting` | `Illuminate\Auth\Events\Attempting` -`auth.login` | `Illuminate\Auth\Events\Login` -`auth.logout` | `Illuminate\Auth\Events\Logout` -`cache.missed` | `Illuminate\Cache\Events\CacheMissed` -`cache.hit` | `Illuminate\Cache\Events\CacheHit` -`cache.write` | `Illuminate\Cache\Events\KeyWritten` -`cache.delete` | `Illuminate\Cache\Events\KeyForgotten` -`connection.{name}.beginTransaction` | `Illuminate\Database\Events\TransactionBeginning` -`connection.{name}.committed` | `Illuminate\Database\Events\TransactionCommitted` -`connection.{name}.rollingBack` | `Illuminate\Database\Events\TransactionRolledBack` -`illuminate.query` | `Illuminate\Database\Events\QueryExecuted` -`illuminate.queue.before` | `Illuminate\Queue\Events\JobProcessing` -`illuminate.queue.after` | `Illuminate\Queue\Events\JobProcessed` -`illuminate.queue.failed` | `Illuminate\Queue\Events\JobFailed` -`illuminate.queue.stopping` | `Illuminate\Queue\Events\WorkerStopping` -`mailer.sending` | `Illuminate\Mail\Events\MessageSending` -`router.matched` | `Illuminate\Routing\Events\RouteMatched` - -Each of these event objects contains **exactly** the same parameters that were passed to the event handler in Laravel 5.1. For example, if you were using `DB::listen` in 5.1.*, you may update your code like so for 5.2.*: - - DB::listen(function ($event) { - dump($event->sql); - dump($event->bindings); - }); - -You may check out each of the new event object classes to see their public properties. - -### Exception Handling - -Your `App\Exceptions\Handler` class' `$dontReport` property should be updated to include at least the following exception types: - - use Illuminate\Validation\ValidationException; - use Illuminate\Auth\Access\AuthorizationException; - use Illuminate\Database\Eloquent\ModelNotFoundException; - use Symfony\Component\HttpKernel\Exception\HttpException; - - /** - * A list of the exception types that should not be reported. - * - * @var array - */ - protected $dontReport = [ - AuthorizationException::class, - HttpException::class, - ModelNotFoundException::class, - ValidationException::class, - ]; - -### Helper Functions - -The `url()` helper function now returns a `Illuminate\Routing\UrlGenerator` instance when no path is provided. - -### Implicit Model Binding - -Laravel 5.2 includes "implicit model binding", a convenient new feature to automatically inject model instances into routes and controllers based on the identifier present in the URI. However, this does change the behavior of routes and controllers that type-hint model instances. - -If you were type-hinting a model instance in your route or controller and were expecting an **empty** model instance to be injected, you should remove this type-hint and create an empty model instance directly within your route or controller; otherwise, Laravel will attempt to retrieve an existing model instance from the database based on the identifier present in the route's URI. - -### IronMQ - -The IronMQ queue driver has been moved into its own package and is no longer shipped with the core framework. - -[http://github.com/LaravelCollective/iron-queue](http://github.com/laravelcollective/iron-queue) - -### Jobs / Queue - -The `php artisan make:job` command now creates a "queued" job class definition by default. If you would like to create a "sync" job, use the `--sync` option when issuing the command. - -### Mail - -The `pretend` mail configuration option has been removed. Instead, use the `log` mail driver, which performs the same function as `pretend` and logs even more information about the mail message. - -### Pagination - -To be consistent with other URLs generated by the framework, the paginator URLs no longer contain a trailing slash. This is unlikely to affect your application. - -### Service Providers - -The `Illuminate\Foundation\Providers\ArtisanServiceProvider` should be removed from your service provider list in your `app.php` configuration file. - -The `Illuminate\Routing\ControllerServiceProvider` should be removed from your service provider list in your `app.php` configuration file. - -### Sessions - -Because of changes to the authentication system, any existing sessions will be invalidated when you upgrade to Laravel 5.2. - -#### Database Session Driver - -A new `database` session driver has been written for the framework which includes more information about the user such as their user ID, IP address, and user-agent. If you would like to continue using the old driver you may specify the `legacy-database` driver in your `session.php` configuration file. - -If you would like to use the new driver, you should add the `user_id (nullable integer)`, `ip_address (nullable string)`, and `user_agent (text)` columns to your session database table. - -### Stringy - -The "Stringy" library is no longer included with the framework. You may install it manually via Composer if you wish to use it in your application. - -### Validation - -#### Exception Types - -The `ValidatesRequests` trait now throws an instance of `Illuminate\Foundation\Validation\ValidationException` instead of throwing an instance of `Illuminate\Http\Exception\HttpResponseException`. This is unlikely to affect your application unless you were manually catching this exception. - - -### Deprecations - -The following features are deprecated in 5.2 and will be removed in the 5.3 release in June 2016: - -- `Illuminate\Contracts\Bus\SelfHandling` contract. Can be removed from jobs. -- The `lists` method on the Collection, query builder and Eloquent query builder objects has been renamed to `pluck`. The method signature remains the same. -- Implicit controller routes using `Route::controller` have been deprecated. Please use explicit route registration in your routes file. This will likely be extracted into a package. -- The `get`, `post`, and other route helper functions have been removed. You may use the `Route` facade instead. -- The `database` session driver from 5.1 has been renamed to `legacy-database` and will be removed. Consult notes on the "database session driver" above for more information. -- The `Str::randomBytes` function has been deprecated in favor of the `random_bytes` native PHP function. -- The `Str::equals` function has been deprecated in favor of the `hash_equals` native PHP function. -- `Illuminate\View\Expression` has been deprecated in favor of `Illuminate\Support\HtmlString`. -- The `WincacheStore` cache driver has been removed. - - -## Upgrading To 5.1.11 - -Laravel 5.1.11 includes support for [authorization](/docs/{{version}}/authorization) and [policies](/docs/{{version}}/authorization#policies). Incorporating these new features into your existing Laravel 5.1 applications is simple. - -> {note} These upgrades are **optional**, and ignoring them will not affect your application. - -#### Create The Policies Directory - -First, create an empty `app/Policies` directory within your application. - -#### Create / Register The AuthServiceProvider & Gate Facade - -Create a `AuthServiceProvider` within your `app/Providers` directory. You may copy the contents of the default provider [from GitHub](https://raw.githubusercontent.com/laravel/laravel/master/app/Providers/AuthServiceProvider.php). Remember to change the provider's namespace if your application is using a custom namespace. After creating the provider, be sure to register it in your `app.php` configuration file's `providers` array. - -Also, you should register the `Gate` facade in your `app.php` configuration file's `aliases` array: - - 'Gate' => Illuminate\Support\Facades\Gate::class, - -#### Update The User Model - -Secondly, use the `Illuminate\Foundation\Auth\Access\Authorizable` trait and `Illuminate\Contracts\Auth\Access\Authorizable` contract on your `App\User` model: - - -## Upgrading To 5.1.0 - -#### Estimated Upgrade Time: Less Than 1 Hour - -### Update `bootstrap/autoload.php` - -Update the `$compiledPath` variable in `bootstrap/autoload.php` to the following: - - $compiledPath = __DIR__.'/cache/compiled.php'; - -### Create `bootstrap/cache` Directory - -Within your `bootstrap` directory, create a `cache` directory (`bootstrap/cache`). Place a `.gitignore` file in this directory with the following contents: - - * - !.gitignore - -This directory should be writable, and will be used by the framework to store temporary optimization files like `compiled.php`, `routes.php`, `config.php`, and `services.json`. - -### Add `BroadcastServiceProvider` Provider - -Within your `config/app.php` configuration file, add `Illuminate\Broadcasting\BroadcastServiceProvider` to the `providers` array. - -### Authentication - -If you are using the provided `AuthController` which uses the `AuthenticatesAndRegistersUsers` trait, you will need to make a few changes to how new users are validated and created. - -First, you no longer need to pass the `Guard` and `Registrar` instances to the base constructor. You can remove these dependencies entirely from your controller's constructor. - -Secondly, the `App\Services\Registrar` class used in Laravel 5.0 is no longer needed. You can simply copy and paste your `validator` and `create` method from this class directly into your `AuthController`. No other changes should need to be made to these methods; however, you should be sure to import the `Validator` facade and your `User` model at the top of your `AuthController`. - -#### Password Controller - -The included `PasswordController` no longer requires any dependencies in its constructor. You may remove both of the dependencies that were required under 5.0. - -### Validation - -If you are overriding the `formatValidationErrors` method on your base controller class, you should now type-hint the `Illuminate\Contracts\Validation\Validator` contract instead of the concrete `Illuminate\Validation\Validator` instance. - -Likewise, if you are overriding the `formatErrors` method on the base form request class, you should now type-hint `Illuminate\Contracts\Validation\Validator` contract instead of the concrete `Illuminate\Validation\Validator` instance. - -### Migrations - -If you have any migrations that rename a column or any migrations that drop columns from a SQLite database, you will need to add the `doctrine/dbal` dependency to your `composer.json` file and run the `composer update` command in your terminal to install the library. - -### Eloquent - -#### The `create` Method - -Eloquent's `create` method can now be called without any parameters. If you are overriding the `create` method in your own models, set the default value of the `$attributes` parameter to an array: - - public static function create(array $attributes = []) - { - // Your custom implementation - } - -#### The `find` Method - -If you are overriding the `find` method in your own models and calling `parent::find()` within your custom method, you should now change it to call the `find` method on the Eloquent query builder: - - public static function find($id, $columns = ['*']) - { - $model = static::query()->find($id, $columns); - - // ... - - return $model; - } - -#### The `lists` Method - -The `lists` method now returns a `Collection` instance instead of a plain array for Eloquent queries. If you would like to convert the `Collection` into a plain array, use the `all` method: - - User::lists('id')->all(); - -Be aware that the Query Builder `lists` method still returns an array. - -#### Date Formatting - -Previously, the storage format for Eloquent date fields could be modified by overriding the `getDateFormat` method on your model. This is still possible; however, for convenience you may simply specify a `$dateFormat` property on the model instead of overriding the method. - -The date format is also now applied when serializing a model to an `array` or JSON. This may change the format of your JSON serialized date fields when migrating from Laravel 5.0 to 5.1. To set a specific date format for serialized models, you may override the `serializeDate(DateTime $date)` method on your model. This method allows you to have granular control over the formatting of serialized Eloquent date fields without changing their storage format. - -### The Collection Class - -#### The `sort` Method - -The `sort` method now returns a fresh collection instance instead of modifying the existing collection: - - $collection = $collection->sort($callback); - -#### The `sortBy` Method - -The `sortBy` method now returns a fresh collection instance instead of modifying the existing collection: - - $collection = $collection->sortBy('name'); - -#### The `groupBy` Method - -The `groupBy` method now returns `Collection` instances for each item in the parent `Collection`. If you would like to convert all of the items back to plain arrays, you may `map` over them: - - $collection->groupBy('type')->map(function($item) - { - return $item->all(); - }); - -#### The `lists` Method - -The `lists` method now returns a `Collection` instance instead of a plain array. If you would like to convert the `Collection` into a plain array, use the `all` method: - - $collection->lists('id')->all(); - -### Commands & Handlers - -The `app/Commands` directory has been renamed to `app/Jobs`. However, you are not required to move all of your commands to the new location, and you may continue using the `make:command` and `handler:command` Artisan commands to generate your classes. - -Likewise, the `app/Handlers` directory has been renamed to `app/Listeners` and now only contains event listeners. However, you are not required to move or rename your existing command and event handlers, and you may continue to use the `handler:event` command to generate event handlers. - -By providing backwards compatibility for the Laravel 5.0 folder structure, you may upgrade your applications to Laravel 5.1 and slowly upgrade your events and commands to their new locations when it is convenient for you or your team. - -### Blade - -The `createMatcher`, `createOpenMatcher`, and `createPlainMatcher` methods have been removed from the Blade compiler. Use the new `directive` method to create custom directives for Blade in Laravel 5.1. Consult the [extending blade](/docs/{{version}}/blade#extending-blade) documentation for more information. - -### Tests - -Add the protected `$baseUrl` property to the `tests/TestCase.php` file: - - protected $baseUrl = 'http://localhost'; - -### Translation Files - -The default directory for published language files for vendor packages has been moved. Move any vendor package language files from `resources/lang/packages/{locale}/{namespace}` to `resources/lang/vendor/{namespace}/{locale}` directory. For example, `Acme/Anvil` package's `acme/anvil::foo` namespaced English language file would be moved from `resources/lang/packages/en/acme/anvil/foo.php` to `resources/lang/vendor/acme/anvil/en/foo.php`. - -### Amazon Web Services SDK - -If you are using the AWS SQS queue driver or the AWS SES e-mail driver, you should update your installed AWS PHP SDK to version 3.0. - -If you are using the Amazon S3 filesystem driver, you will need to update the corresponding Flysystem package via Composer: - -- Amazon S3: `league/flysystem-aws-s3-v3 ~1.0` - -### Deprecations - -The following Laravel features have been deprecated and will be removed entirely with the release of Laravel 5.2 in December 2015: - -
    -- Route filters have been deprecated in preference of [middleware](/docs/{{version}}/middleware). -- The `Illuminate\Contracts\Routing\Middleware` contract has been deprecated. No contract is required on your middleware. In addition, the `TerminableMiddleware` contract has also been deprecated. Instead of implementing the interface, simply define a `terminate` method on your middleware. -- The `Illuminate\Contracts\Queue\ShouldBeQueued` contract has been deprecated in favor of `Illuminate\Contracts\Queue\ShouldQueue`. -- Iron.io "push queues" have been deprecated in favor of typical Iron.io queues and [queue listeners](/docs/{{version}}/queues#running-the-queue-listener). -- The `Illuminate\Foundation\Bus\DispatchesCommands` trait has been deprecated and renamed to `Illuminate\Foundation\Bus\DispatchesJobs`. -- `Illuminate\Container\BindingResolutionException` has been moved to `Illuminate\Contracts\Container\BindingResolutionException`. -- The service container's `bindShared` method has been deprecated in favor of the `singleton` method. -- The Eloquent and query builder `pluck` method has been deprecated and renamed to `value`. -- The collection `fetch` method has been deprecated in favor of the `pluck` method. -- The `array_fetch` helper has been deprecated in favor of the `array_pluck` method. -
    - - -## Upgrading To 5.0.16 - -In your `bootstrap/autoload.php` file, update the `$compiledPath` variable to: - - $compiledPath = __DIR__.'/../vendor/compiled.php'; - - -### Service Providers - -The `App\Providers\BusServiceProvider` may be removed from your service provider list in your `app.php` configuration file. - -The `App\Providers\ConfigServiceProvider` may be removed from your service provider list in your `app.php` configuration file. - - - -## Upgrading To 5.0 From 4.2 - -### Fresh Install, Then Migrate - -The recommended method of upgrading is to create a new Laravel `5.0` install and then to copy your `4.2` site's unique application files into the new application. This would include controllers, routes, Eloquent models, Artisan commands, assets, and other code specific files to your application. - -To start, [install a new Laravel 5.0 application](/docs/5.0/installation) into a fresh directory in your local environment. Do not install any versions newer than 5.0 yet, since we need to complete the migration steps for 5.0 first. We'll discuss each piece of the migration process in further detail below. - -### Composer Dependencies & Packages - -Don't forget to copy any additional Composer dependencies into your 5.0 application. This includes third-party code such as SDKs. - -Some Laravel-specific packages may not be compatible with Laravel 5 on initial release. Check with your package's maintainer to determine the proper version of the package for Laravel 5. Once you have added any additional Composer dependencies your application needs, run `composer update`. - -### Namespacing - -By default, Laravel 4 applications did not utilize namespacing within your application code. So, for example, all Eloquent models and controllers simply lived in the "global" namespace. For a quicker migration, you can simply leave these classes in the global namespace in Laravel 5 as well. - -### Configuration - -#### Migrating Environment Variables - -Copy the new `.env.example` file to `.env`, which is the `5.0` equivalent of the old `.env.php` file. Set any appropriate values there, like your `APP_ENV` and `APP_KEY` (your encryption key), your database credentials, and your cache and session drivers. - -Additionally, copy any custom values you had in your old `.env.php` file and place them in both `.env` (the real value for your local environment) and `.env.example` (a sample instructional value for other team members). - -For more information on environment configuration, view the [full documentation](/docs/{{version}}/installation#environment-configuration). - -> {note} You will need to place the appropriate `.env` file and values on your production server before deploying your Laravel 5 application. - -#### Configuration Files - -Laravel 5.0 no longer uses `app/config/{environmentName}/` directories to provide specific configuration files for a given environment. Instead, move any configuration values that vary by environment into `.env`, and then access them in your configuration files using `env('key', 'default value')`. You will see examples of this in the `config/database.php` configuration file. - -Set the config files in the `config/` directory to represent either the values that are consistent across all of your environments, or set them to use `env()` to load values that vary by environment. - -Remember, if you add more keys to `.env` file, add sample values to the `.env.example` file as well. This will help your other team members create their own `.env` files. - -### Routes - -Copy and paste your old `routes.php` file into your new `app/Http/routes.php`. - -### Controllers - -Next, move all of your controllers into the `app/Http/Controllers` directory. Since we are not going to migrate to full namespacing in this guide, add the `app/Http/Controllers` directory to the `classmap` directive of your `composer.json` file. Next, you can remove the namespace from the abstract `app/Http/Controllers/Controller.php` base class. Verify that your migrated controllers are extending this base class. - -In your `app/Providers/RouteServiceProvider.php` file, set the `namespace` property to `null`. - -### Route Filters - -Copy your filter bindings from `app/filters.php` and place them into the `boot()` method of `app/Providers/RouteServiceProvider.php`. Add `use Illuminate\Support\Facades\Route;` in the `app/Providers/RouteServiceProvider.php` in order to continue using the `Route` Facade. - -You do not need to move over any of the default Laravel 4.0 filters such as `auth` and `csrf`; they're all here, but as middleware. Edit any routes or controllers that reference the old default filters (e.g. `['before' => 'auth']`) and change them to reference the new middleware (e.g. `['middleware' => 'auth'].`) - -Filters are not removed in Laravel 5. You can still bind and use your own custom filters using `before` and `after`. - -### Global CSRF - -By default, [CSRF protection](/docs/{{version}}/routing#csrf-protection) is enabled on all routes. If you'd like to disable this, or only manually enable it on certain routes, remove this line from `App\Http\Kernel`'s `middleware` array: - - 'App\Http\Middleware\VerifyCsrfToken', - -If you want to use it elsewhere, add this line to `$routeMiddleware`: - - 'csrf' => 'App\Http\Middleware\VerifyCsrfToken', - -Now you can add the middleware to individual routes / controllers using `['middleware' => 'csrf']` on the route. For more information on middleware, consult the [full documentation](/docs/{{version}}/middleware). - -### Eloquent Models - -Feel free to create a new `app/Models` directory to house your Eloquent models. Again, add this directory to the `classmap` directive of your `composer.json` file. - -Update any models using `SoftDeletingTrait` to use `Illuminate\Database\Eloquent\SoftDeletes`. - -#### Eloquent Caching - -Eloquent no longer provides the `remember` method for caching queries. You now are responsible for caching your queries manually using the `Cache::remember` function. For more information on caching, consult the [full documentation](/docs/{{version}}/cache). - -### User Authentication Model - -To upgrade your `User` model for Laravel 5's authentication system, follow these instructions: - -**Delete the following from your `use` block:** - -```php -use Illuminate\Auth\UserInterface; -use Illuminate\Auth\Reminders\RemindableInterface; -``` - -**Add the following to your `use` block:** - -```php -use Illuminate\Auth\Authenticatable; -use Illuminate\Auth\Passwords\CanResetPassword; -use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; -use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract; -``` - -**Remove the UserInterface and RemindableInterface interfaces.** - -**Mark the class as implementing the following interfaces:** - -```php -implements AuthenticatableContract, CanResetPasswordContract -``` - -**Include the following traits within the class declaration:** - -```php -use Authenticatable, CanResetPassword; -``` - -**If you used them, remove `Illuminate\Auth\Reminders\RemindableTrait` and `Illuminate\Auth\UserTrait` from your use block and your class declaration.** - -### Cashier User Changes - -The name of the trait and interface used by [Laravel Cashier](/docs/{{version}}/billing) has changed. Instead of using `BillableTrait`, use the `Laravel\Cashier\Billable` trait. And, instead of `Laravel\Cashier\BillableInterface` implement the `Laravel\Cashier\Contracts\Billable` interface instead. No other method changes are required. - -### Artisan Commands - -Move all of your command classes from your old `app/commands` directory to the new `app/Console/Commands` directory. Next, add the `app/Console/Commands` directory to the `classmap` directive of your `composer.json` file. - -Then, copy your list of Artisan commands from `start/artisan.php` into the `commands` array of the `app/Console/Kernel.php` file. - -### Database Migrations & Seeds - -Delete the two migrations included with Laravel 5.0, since you should already have the users table in your database. - -Move all of your migration classes from the old `app/database/migrations` directory to the new `database/migrations`. All of your seeds should be moved from `app/database/seeds` to `database/seeds`. - -### Global IoC Bindings - -If you have any [service container](/docs/{{version}}/container) bindings in `start/global.php`, move them all to the `register` method of the `app/Providers/AppServiceProvider.php` file. You may need to import the `App` facade. - -Optionally, you may break these bindings up into separate service providers by category. - -### Views - -Move your views from `app/views` to the new `resources/views` directory. - -### Blade Tag Changes - -For better security by default, Laravel 5.0 escapes all output from both the `{{ }}` and `{{{ }}}` Blade directives. A new `{!! !!}` directive has been introduced to display raw, unescaped output. The most secure option when upgrading your application is to only use the new `{!! !!}` directive when you are **certain** that it is safe to display raw output. - -However, if you **must** use the old Blade syntax, add the following lines at the bottom of `AppServiceProvider@register`: - -```php -\Blade::setRawTags('{{', '}}'); -\Blade::setContentTags('{{{', '}}}'); -\Blade::setEscapedContentTags('{{{', '}}}'); -``` - -This should not be done lightly, and may make your application more vulnerable to XSS exploits. Also, comments with `{{--` will no longer work. - -### Translation Files - -Move your language files from `app/lang` to the new `resources/lang` directory. - -### Public Directory - -Copy your application's public assets from your `4.2` application's `public` directory to your new application's `public` directory. Be sure to keep the `5.0` version of `index.php`. - -### Tests - -Move your tests from `app/tests` to the new `tests` directory. - -### Misc. Files - -Copy in any other files in your project. For example, `.scrutinizer.yml`, `bower.json` and other similar tooling configuration files. - -You may move your Sass, Less, or CoffeeScript to any location you wish. The `resources/assets` directory could be a good default location. - -### Form & HTML Helpers - -If you're using Form or HTML helpers, you will see an error stating `class 'Form' not found` or `class 'Html' not found`. The Form and HTML helpers have been deprecated in Laravel 5.0; however, there are community-driven replacements such as those maintained by the [Laravel Collective](http://laravelcollective.com/docs/{{version}}/html). - -For example, you may add `"laravelcollective/html": "~5.0"` to your `composer.json` file's `require` section. - -You'll also need to add the Form and HTML facades and service provider. Edit `config/app.php` and add this line to the 'providers' array: - - 'Collective\Html\HtmlServiceProvider', - -Next, add these lines to the 'aliases' array: - - 'Form' => 'Collective\Html\FormFacade', - 'Html' => 'Collective\Html\HtmlFacade', - -### CacheManager - -If your application code was injecting `Illuminate\Cache\CacheManager` to get a non-Facade version of Laravel's cache, inject `Illuminate\Contracts\Cache\Repository` instead. - -### Pagination - -Replace any calls to `$paginator->links()` with `$paginator->render()`. - -Replace any calls to `$paginator->getFrom()` and `$paginator->getTo()` with `$paginator->firstItem()` and `$paginator->lastItem()` respectively. - -Remove the "get" prefix from calls to `$paginator->getPerPage()`, `$paginator->getCurrentPage()`, `$paginator->getLastPage()` and `$paginator->getTotal()` (e.g. `$paginator->perPage()`). - -### Beanstalk Queuing - -Laravel 5.0 now requires `"pda/pheanstalk": "~3.0"` instead of `"pda/pheanstalk": "~2.1"`. - -### Remote - -The Remote component has been deprecated. - -### Workbench - -The Workbench component has been deprecated. - ## Upgrading To 4.2 From 4.1 @@ -1104,38 +14,32 @@ Laravel 4.2 requires PHP 5.4.0 or greater. ### Encryption Defaults -Add a new `cipher` option in your `app/config/app.php` configuration file. The value of this option should be `MCRYPT_RIJNDAEL_256`. +Add a new `cipher` option in your `app/config/app.php` configuration file. The value of this option shuold be `MCRYPT_RIJNDAEL_256`. - 'cipher' => MCRYPT_RIJNDAEL_256 + 'cipher' => MCRYPT_RIJNDAEL_256 -This setting may be used to control the default cipher used by the Laravel encryption facilities. - -> {note} In Laravel 4.2, the default cipher is `MCRYPT_RIJNDAEL_128` (AES), which is considered to be the most secure cipher. Changing the cipher back to `MCRYPT_RIJNDAEL_256` is required to decrypt cookies/values that were encrypted in Laravel <= 4.1 +This seting may be used to control the default cipher used by the Laravel envryption facilities. ### Soft Deleting Models Now Use Traits -If you are using soft deleting models, the `softDeletes` property has been removed. You must now use the `SoftDeletingTrait` like so: +If you are using soft deleting models, the `softDeletes` property has been removed. You should now use the `SoftDeletingTrait` like so: - use Illuminate\Database\Eloquent\SoftDeletingTrait; + use Illuminate\Database\Eloquent\SoftDeletingTrait; - class User extends Eloquent - { - use SoftDeletingTrait; - } + class User extends Eloquent { + use SoftDeletingTrait; + } -You must also manually add the `deleted_at` column to your `dates` property: +You should also manually add the `deleted_at` column to your `dates` property: - class User extends Eloquent - { - use SoftDeletingTrait; + class User extends Eloquent { + use SoftDeletingTrait; - protected $dates = ['deleted_at']; - } + protected $dates = ['deleted_at']; + } The API for all soft delete operations remains the same. -> {note} The `SoftDeletingTrait` can not be applied on a base model. It must be used on an actual model class. - ### View / Pagination Environment Renamed If you are directly referencing the `Illuminate\View\Environment` class or `Illuminate\Pagination\Environment` class, update your code to reference `Illuminate\View\Factory` and `Illuminate\Pagination\Factory` instead. These two classes have been renamed to better reflect their function. @@ -1144,18 +48,12 @@ If you are directly referencing the `Illuminate\View\Environment` class or `Illu If you are extending the `Illuminate\Pagination\Presenter` class, the abstract method `getPageLinkWrapper` signature has changed to add the `rel` argument: - abstract public function getPageLinkWrapper($url, $page, $rel = null); - -### Iron.Io Queue Encryption - -If you are using the Iron.io queue driver, you will need to add a new `encrypt` option to your queue configuration file: - - 'encrypt' => true + abstract public function getPageLinkWrapper($url, $page, $rel = null); ## Upgrading To 4.1.29 From <= 4.1.x -Laravel 4.1.29 improves the column quoting for all database drivers. This protects your application from some mass assignment vulnerabilities when **not** using the `fillable` property on models. If you are using the `fillable` property on your models to protect against mass assignment, your application is not vulnerable. However, if you are using `guarded` and are passing a user controlled array into an "update" or "save" type function, you should upgrade to `4.1.29` immediately as your application may be at risk of mass assignment. +Laravel 4.1.29 improves the column quoting for all database drivers. This protects your application from some mass assignment vulnerabilities when **not** using the `fillable` property on models. If you are using the `fillable` property on your models to protect against mass assignemnt, your application is not vulerable. However, if you are using `guarded` and are passing a user controlled array into an "update" or "save" type function, you should upgrade to `4.1.29` immediately as your application may be at risk of mass assignment. To upgrade to Laravel 4.1.29, simply `composer update`. No breaking changes are introduced in this release. @@ -1172,30 +70,30 @@ First, add a new, nullable `remember_token` of VARCHAR(100), TEXT, or equivalent Next, if you are using the Eloquent authentication driver, update your `User` class with the following three methods: - public function getRememberToken() - { - return $this->remember_token; - } + public function getRememberToken() + { + return $this->remember_token; + } - public function setRememberToken($value) - { - $this->remember_token = $value; - } + public function setRememberToken($value) + { + $this->remember_token = $value; + } - public function getRememberTokenName() - { - return 'remember_token'; - } + public function getRememberTokenName() + { + return 'remember_token'; + } -> {note} All existing "remember me" sessions will be invalidated by this change, so all users will be forced to re-authenticate with your application. +> **Note:** All existing "remember me" sessions will be invalidated by this change, so all users will be forced to re-authenticate with your application. ### Package Maintainers Two new methods were added to the `Illuminate\Auth\UserProviderInterface` interface. Sample implementations may be found in the default drivers: - public function retrieveByToken($identifier, $token); + public function retrieveByToken($identifier, $token); - public function updateRememberToken(UserInterface $user, $token); + public function updateRememberToken(UserInterface $user, $token); The `Illuminate\Auth\UserInterface` also received the three new methods described in the "Upgrade Path". @@ -1208,23 +106,23 @@ To upgrade your application to Laravel 4.1, change your `laravel/framework` vers ### Replacing Files -Replace your `public/index.php` file with [this fresh copy from the repository](https://github.com/laravel/laravel/blob/v4.1.0/public/index.php). +Replace your `public/index.php` file with [this fresh copy from the repository](https://github.com/laravel/laravel/blob/master/public/index.php). -Replace your `artisan` file with [this fresh copy from the repository](https://github.com/laravel/laravel/blob/v4.1.0/artisan). +Replace your `artisan` file with [this fresh copy from the repository](https://github.com/laravel/laravel/blob/master/artisan). ### Adding Configuration Files & Options -Update your `aliases` and `providers` arrays in your `app/config/app.php` configuration file. The updated values for these arrays can be found [in this file](https://github.com/laravel/laravel/blob/v4.1.0/app/config/app.php). Be sure to add your custom and package service providers / aliases back to the arrays. +Update your `aliases` and `providers` arrays in your `app/config/app.php` configuration file. The updated values for these arrays can be found [in this file](https://github.com/laravel/laravel/blob/master/app/config/app.php). Be sure to add your custom and package service providers / aliases back to the arrays. -Add the new `app/config/remote.php` file [from the repository](https://github.com/laravel/laravel/blob/v4.1.0/app/config/remote.php). +Add the new `app/config/remote.php` file [from the repository](https://github.com/laravel/laravel/blob/master/app/config/remote.php). Add the new `expire_on_close` configuration option to your `app/config/session.php` file. The default value should be `false`. Add the new `failed` configuration section to your `app/config/queue.php` file. Here are the default values for the section: - 'failed' => [ - 'database' => 'mysql', 'table' => 'failed_jobs', - ], + 'failed' => array( + 'database' => 'mysql', 'table' => 'failed_jobs', + ), **(Optional)** Update the `pagination` configuration option in your `app/config/view.php` file to `pagination::slider-3`. @@ -1234,9 +132,9 @@ If `app/controllers/BaseController.php` has a `use` statement at the top, change ### Password Reminders Updates -Password reminders have been overhauled for greater flexibility. You may examine the new stub controller by running the `php artisan auth:reminders-controller` Artisan command. You may also browse the [updated documentation](/docs/security#password-reminders-and-reset) and update your application accordingly. +Password reminders have been overhauled for greater flexibility. You may examine the new stub controller by running the `php artisan auth:reminders-controller` Artisan command. You may also browse the [updated documentation](security#password-reminders-and-reset.md) and update your application accordingly. -Update your `app/lang/en/reminders.php` language file to match [this updated file](https://github.com/laravel/laravel/blob/v4.1.0/app/lang/en/reminders.php). +Update your `app/lang/en/reminders.php` language file to match [this updated file](https://github.com/laravel/laravel/blob/master/app/lang/en/reminders.php). ### Environment Detection Updates @@ -1250,7 +148,7 @@ Laravel now generates a single log file: `app/storage/logs/laravel.log`. However In your `bootstrap/start.php` file, remove the call to `$app->redirectIfTrailingSlash()`. This method is no longer needed as this functionality is now handled by the `.htaccess` file included with the framework. -Next, replace your Apache `.htaccess` file with [this new one](https://github.com/laravel/laravel/blob/v4.1.0/public/.htaccess) that handles trailing slashes. +Next, replace your Apache `.htaccess` file with [this new one](https://github.com/laravel/laravel/blob/master/public/.htaccess) that handles trailing slashes. ### Current Route Access diff --git a/valet.md b/valet.md deleted file mode 100644 index b7ff823..0000000 --- a/valet.md +++ /dev/null @@ -1,230 +0,0 @@ -# Laravel Valet - -- [Introduction](#introduction) - - [Valet Or Homestead](#valet-or-homestead) -- [Installation](#installation) -- [Release Notes](#release-notes) -- [Serving Sites](#serving-sites) - - [The "Park" Command](#the-park-command) - - [The "Link" Command](#the-link-command) - - [Securing Sites With TLS](#securing-sites) -- [Sharing Sites](#sharing-sites) -- [Viewing Logs](#viewing-logs) -- [Custom Valet Drivers](#custom-valet-drivers) -- [Other Valet Commands](#other-valet-commands) - - -## Introduction - -Valet is a Laravel development environment for Mac minimalists. No Vagrant, No Apache, No Nginx, No `/etc/hosts` file. You can even share your sites publicly using local tunnels. _Yeah, we like it too._ - -Laravel Valet configures your Mac to always run [Caddy](https://caddyserver.com) in the background when your machine starts. Then, using [DnsMasq](https://en.wikipedia.org/wiki/Dnsmasq), Valet proxies all requests on the `*.dev` domain to point to sites installed on your local machine. - -In other words, a blazing fast Laravel development environment that uses roughly 7 MB of RAM. Valet isn't a complete replacement for Vagrant or Homestead, but provides a great alternative if you want flexible basics, prefer extreme speed, or are working on a machine with a limited amount of RAM. - -Out of the box, Valet support includes, but is not limited to: - -
    -- [Laravel](https://laravel.com) -- [Lumen](https://lumen.laravel.com) -- [Symfony](https://symfony.com) -- [Zend](http://framework.zend.com) -- [CakePHP 3](http://cakephp.org) -- [WordPress](https://wordpress.org) -- [Bedrock](https://roots.io/bedrock) -- [Craft](https://craftcms.com) -- [Statamic](https://statamic.com) -- [Jigsaw](http://jigsaw.tighten.co) -- Static HTML -
    - -However, you may extend Valet with your own [custom drivers](#custom-valet-drivers). - - -### Valet Or Homestead - -As you may know, Laravel offers [Homestead](/docs/{{version}}/homestead), another local Laravel development environment. Homestead and Valet differ in regards to their intended audience and their approach to local development. Homestead offers an entire Ubuntu virtual machine with automated Nginx configuration. Homestead is a wonderful choice if you want a fully virtualized Linux development environment or are on Windows / Linux. - -Valet only supports Mac, and requires you to install PHP and a database server directly onto your local machine. This is easily achieved by using [Homebrew](http://brew.sh/) with commands like `brew install php70` and `brew install mariadb`. Valet provides a blazing fast local development environment with minimal resource consumption, so it's great for developers who only require PHP / MySQL and do not need a fully virtualized development environment. - -Both Valet and Homestead are great choices for configuring your Laravel development environment. Which one you choose will depend on your personal taste and your team's needs. - - -## Installation - -**Valet requires macOS and [Homebrew](http://brew.sh/). Before installation, you should make sure that no other programs such as Apache or Nginx are binding to your local machine's port 80.** - -
    -- Install or update [Homebrew](http://brew.sh/) to the latest version using `brew update`. -- Install PHP 7.0 using Homebrew via `brew install homebrew/php/php70`. -- Install Valet with Composer via `composer global require laravel/valet`. Make sure the `~/.composer/vendor/bin` directory is in your system's "PATH". -- Run the `valet install` command. This will configure and install Valet and DnsMasq, and register Valet's daemon to launch when your system starts. -
    - -Once Valet is installed, try pinging any `*.dev` domain on your terminal using a command such as `ping foobar.dev`. If Valet is installed correctly you should see this domain responding on `127.0.0.1`. - -Valet will automatically start its daemon each time your machine boots. There is no need to run `valet start` or `valet install` ever again once the initial Valet installation is complete. - -#### Using Another Domain - -By default, Valet serves your projects using the `.dev` TLD. If you'd like to use another domain, you can do so using the `valet domain tld-name` command. - -For example, if you'd like to use `.app` instead of `.dev`, run `valet domain app` and Valet will start serving your projects at `*.app` automatically. - -#### Database - -If you need a database, try MariaDB by running `brew install mariadb` on your command line. You can connect to the database at `127.0.0.1` using the `root` username and an empty string for the password. - - -## Release Notes - -### Version 1.1.5 - -The 1.1.5 release of Valet brings a variety of internal improvements. - -#### Upgrade Instructions - -After updating your Valet installation using `composer global update`, you should run the `valet install` command in your terminal. - -### Version 1.1.0 - -The 1.1.0 release of Valet brings a variety of great improvements. The built-in PHP server has been replaced with [Caddy](https://caddyserver.com/) for serving incoming HTTP requests. Introducing Caddy allows for a variety of future improvements and allows Valet sites to make HTTP requests to other Valet sites without blocking the built-in PHP server. - -#### Upgrade Instructions - -After updating your Valet installation using `composer global update`, you should run the `valet install` command in your terminal to create the new Caddy daemon file on your system. - - -## Serving Sites - -Once Valet is installed, you're ready to start serving sites. Valet provides two commands to help you serve your Laravel sites: `park` and `link`. - - -**The `park` Command** - -
    -- Create a new directory on your Mac by running something like `mkdir ~/Sites`. Next, `cd ~/Sites` and run `valet park`. This command will register your current working directory as a path that Valet should search for sites. -- Next, create a new Laravel site within this directory: `laravel new blog`. -- Open `http://blog.dev` in your browser. -
    - -**That's all there is to it.** Now, any Laravel project you create within your "parked" directory will automatically be served using the `http://folder-name.dev` convention. - - -**The `link` Command** - -The `link` command may also be used to serve your Laravel sites. This command is useful if you want to serve a single site in a directory and not the entire directory. - -
    -- To use the command, navigate to one of your projects and run `valet link app-name` in your terminal. Valet will create a symbolic link in `~/.valet/Sites` which points to your current working directory. -- After running the `link` command, you can access the site in your browser at `http://app-name.dev`. -
    - -To see a listing of all of your linked directories, run the `valet links` command. You may use `valet unlink app-name` to destroy the symbolic link. - - -**Securing Sites With TLS** - -By default, Valet serves sites over plain HTTP. However, if you would like to serve a site over encrypted TLS using HTTP/2, use the `secure` command. For example, if your site is being served by Valet on the `laravel.dev` domain, you should run the following command to secure it: - - valet secure laravel - -To "unsecure" a site and revert back to serving its traffic over plain HTTP, use the `unsecure` command. Like the `secure` command, this command accepts the host name that you wish to unsecure: - - valet unsecure laravel - - -## Sharing Sites - -Valet even includes a command to share your local sites with the world. No additional software installation is required once Valet is installed. - -To share a site, navigate to the site's directory in your terminal and run the `valet share` command. A publicly accessible URL will be inserted into your clipboard and is ready to paste directly into your browser. That's it. - -To stop sharing your site, hit `Control + C` to cancel the process. - - -## Viewing Logs - -If you would like to stream all of the logs for all of your sites to your terminal, run the `valet logs` command. New log entries will display in your terminal as they occur. This is a great way to stay on top of all of your log files without ever having to leave your terminal. - - -## Custom Valet Drivers - -You can write your own Valet "driver" to serve PHP applications running on another framework or CMS that is not natively supported by Valet. When you install Valet, a `~/.valet/Drivers` directory is created which contains a `SampleValetDriver.php` file. This file contains a sample driver implementation to demonstrate how to write a custom driver. Writing a driver only requires you to implement three methods: `serves`, `isStaticFile`, and `frontControllerPath`. - -All three methods receive the `$sitePath`, `$siteName`, and `$uri` values as their arguments. The `$sitePath` is the fully qualified path to the site being served on your machine, such as `/Users/Lisa/Sites/my-project`. The `$siteName` is the "host" / "site name" portion of the domain (`my-project`). The `$uri` is the incoming request URI (`/foo/bar`). - -Once you have completed your custom Valet driver, place it in the `~/.valet/Drivers` directory using the `FrameworkValetDriver.php` naming convention. For example, if you are writing a custom valet driver for WordPress, your file name should be `WordPressValetDriver.php`. - -Let's take at a sample implementation of each method your custom Valet driver should implement. - -#### The `serves` Method - -The `serves` method should return `true` if your driver should handle the incoming request. Otherwise, the method should return `false`. So, within this method you should attempt to determine if the given `$sitePath` contains a project of the type you are trying to serve. - -For example, let's pretend we are writing a `WordPressValetDriver`. Our serve method might look something like this: - - /** - * Determine if the driver serves the request. - * - * @param string $sitePath - * @param string $siteName - * @param string $uri - * @return void - */ - public function serves($sitePath, $siteName, $uri) - { - return is_dir($sitePath.'/wp-admin'); - } - -#### The `isStaticFile` Method - -The `isStaticFile` should determine if the incoming request is for a file that is "static", such as an image or a stylesheet. If the file is static, the method should return the fully qualified path to the static file on disk. If the incoming request is not for a static file, the method should return `false`: - - /** - * Determine if the incoming request is for a static file. - * - * @param string $sitePath - * @param string $siteName - * @param string $uri - * @return string|false - */ - public function isStaticFile($sitePath, $siteName, $uri) - { - if (file_exists($staticFilePath = $sitePath.'/public/'.$uri)) { - return $staticFilePath; - } - - return false; - } - -> {note} The `isStaticFile` method will only be called if the `serves` method returns `true` for the incoming request and the request URI is not `/`. - -#### The `frontControllerPath` Method - -The `frontControllerPath` method should return the fully qualified path to your application's "front controller", which is typically your "index.php" file or equivalent: - - /** - * Get the fully resolved path to the application's front controller. - * - * @param string $sitePath - * @param string $siteName - * @param string $uri - * @return string - */ - public function frontControllerPath($sitePath, $siteName, $uri) - { - return $sitePath.'/public/index.php'; - } - - -## Other Valet Commands - -Command | Description -------------- | ------------- -`valet forget` | Run this command from a "parked" directory to remove it from the parked directory list. -`valet paths` | View all of your "parked" paths. -`valet restart` | Restart the Valet daemon. -`valet start` | Start the Valet daemon. -`valet stop` | Stop the Valet daemon. -`valet uninstall` | Uninstall the Valet daemon entirely. diff --git a/validation.md b/validation.md old mode 100644 new mode 100755 index 0440501..8037945 --- a/validation.md +++ b/validation.md @@ -1,635 +1,282 @@ -# Validation - -- [Introduction](#introduction) -- [Validation Quickstart](#validation-quickstart) - - [Defining The Routes](#quick-defining-the-routes) - - [Creating The Controller](#quick-creating-the-controller) - - [Writing The Validation Logic](#quick-writing-the-validation-logic) - - [Displaying The Validation Errors](#quick-displaying-the-validation-errors) -- [Form Request Validation](#form-request-validation) - - [Creating Form Requests](#creating-form-requests) - - [Authorizing Form Requests](#authorizing-form-requests) - - [Customizing The Error Format](#customizing-the-error-format) - - [Customizing The Error Messages](#customizing-the-error-messages) -- [Manually Creating Validators](#manually-creating-validators) - - [Automatic Redirection](#automatic-redirection) - - [Named Error Bags](#named-error-bags) - - [After Validation Hook](#after-validation-hook) +# စိစစ်ခြင်း + +- [အခြေခံအသုံးပြုပုံ](#basic-usage) - [Working With Error Messages](#working-with-error-messages) - - [Custom Error Messages](#custom-error-messages) +- [Error Messages & Views](#error-messages-and-views) - [Available Validation Rules](#available-validation-rules) - [Conditionally Adding Rules](#conditionally-adding-rules) -- [Validating Arrays](#validating-arrays) +- [Custom Error Messages](#custom-error-messages) - [Custom Validation Rules](#custom-validation-rules) - -## Introduction - -Laravel provides several different approaches to validate your application's incoming data. By default, Laravel's base controller class uses a `ValidatesRequests` trait which provides a convenient method to validate incoming HTTP request with a variety of powerful validation rules. - - -## Validation Quickstart - -To learn about Laravel's powerful validation features, let's look at a complete example of validating a form and displaying the error messages back to the user. - - -### Defining The Routes - -First, let's assume we have the following routes defined in our `routes/web.php` file: - - Route::get('post/create', 'PostController@create'); - - Route::post('post', 'PostController@store'); - -Of course, the `GET` route will display a form for the user to create a new blog post, while the `POST` route will store the new blog post in the database. - - -### Creating The Controller - -Next, let's take a look at a simple controller that handles these routes. We'll leave the `store` method empty for now: - - -### Writing The Validation Logic - -Now we are ready to fill in our `store` method with the logic to validate the new blog post. If you examine your application's base controller (`App\Http\Controllers\Controller`) class, you will see that the class uses a `ValidatesRequests` trait. This trait provides a convenient `validate` method to all of your controllers. - -The `validate` method accepts an incoming HTTP request and a set of validation rules. If the validation rules pass, your code will keep executing normally; however, if validation fails, an exception will be thrown and the proper error response will automatically be sent back to the user. In the case of a traditional HTTP request, a redirect response will be generated, while a JSON response will be sent for AJAX requests. - -To get a better understanding of the `validate` method, let's jump back into the `store` method: - - /** - * Store a new blog post. - * - * @param Request $request - * @return Response - */ - public function store(Request $request) - { - $this->validate($request, [ - 'title' => 'required|unique:posts|max:255', - 'body' => 'required', - ]); - - // The blog post is valid, store in database... - } - -As you can see, we simply pass the incoming HTTP request and desired validation rules into the `validate` method. Again, if the validation fails, the proper response will automatically be generated. If the validation passes, our controller will continue executing normally. - -#### Stopping On First Validation Failure - -Sometimes you may wish to stop running validation rules on an attribute after the first validation failure. To do so, assign the `bail` rule to the attribute: - - $this->validate($request, [ - 'title' => 'bail|required|unique:posts|max:255', - 'body' => 'required', - ]); - -In this example, if the `required` rule on the `title` attribute fails, the `unique` rule will not be checked. Rules will be validated in the order they are assigned. - -#### A Note On Nested Attributes - -If your HTTP request contains "nested" parameters, you may specify them in your validation rules using "dot" syntax: - - $this->validate($request, [ - 'title' => 'required|unique:posts|max:255', - 'author.name' => 'required', - 'author.description' => 'required', - ]); - - -### Displaying The Validation Errors - -So, what if the incoming request parameters do not pass the given validation rules? As mentioned previously, Laravel will automatically redirect the user back to their previous location. In addition, all of the validation errors will automatically be [flashed to the session](/docs/{{version}}/session#flash-data). - -Again, notice that we did not have to explicitly bind the error messages to the view in our `GET` route. This is because Laravel will check for errors in the session data, and automatically bind them to the view if they are available. The `$errors` variable will be an instance of `Illuminate\Support\MessageBag`. For more information on working with this object, [check out its documentation](#working-with-error-messages). - -> {tip} The `$errors` variable is bound to the view by the `Illuminate\View\Middleware\ShareErrorsFromSession` middleware, which is provided by the `web` middleware group. **When this middleware is applied an `$errors` variable will always be available in your views**, allowing you to conveniently assume the `$errors` variable is always defined and can be safely used. - -So, in our example, the user will be redirected to our controller's `create` method when validation fails, allowing us to display the error messages in the view: + +## အခြေခံအသုံးပြုပုံ - +Laravel အနေဖြင့် data များကို စိစစ်ရာတွင် ရိုးရှင်း အဆင်ပြေသော နည်းလမ်းများကို အသုံးပြုထားသည်။ error message များကို `Validation` class မှ တဆင့် ထုတ်ယူနိုင်သည်။ -

    Create Post

    +#### အခြေခံအသုံးပြုပုံ ဥပမာ - @if (count($errors) > 0) -
    -
      - @foreach ($errors->all() as $error) -
    • {{ $error }}
    • - @endforeach -
    -
    - @endif + $validator = Validator::make( + array('name' => 'Dayle'), + array('name' => 'required|min:5') + ); - +Validation ပြုလုပ်ရာတွင် `make` method ဟုသည့် method ကို အသုံးပြုပြီး array တွင်းပါရှိမည့် ပထမ argument မှာ data ဖြစ်ပြီး ဒုတိယ argument မှာ ထို data များကို စိစစ်မည့် rule များကို ထည့်သွင်းရမည်။ - -#### Customizing The Flashed Error Format -If you wish to customize the format of the validation errors that are flashed to the session when validation fails, override the `formatValidationErrors` on your base controller. Don't forget to import the `Illuminate\Contracts\Validation\Validator` class at the top of the file: +#### Array ကို အသုံးပြု၍ Rule များ သတ်မှတ်ခြင်း - 'Dayle'), + array('name' => array('required', 'min:5')) + ); - use Illuminate\Foundation\Bus\DispatchesJobs; - use Illuminate\Contracts\Validation\Validator; - use Illuminate\Routing\Controller as BaseController; - use Illuminate\Foundation\Validation\ValidatesRequests; +#### Fields များစွာကို စိစစ်ခြင်း - abstract class Controller extends BaseController - { - use DispatchesJobs, ValidatesRequests; + $validator = Validator::make( + array( + 'name' => 'Dayle', + 'password' => 'lamepassword', + 'email' => 'email@example.com' + ), + array( + 'name' => 'required', + 'password' => 'required|min:8', + 'email' => 'required|email|unique:users' + ) + ); - /** - * {@inheritdoc} - */ - protected function formatValidationErrors(Validator $validator) - { - return $validator->errors()->all(); - } - } +`Validator` instance ကို ပြုလုပ်ပြီးပါက `fails` သို ့မဟုတ် `passes` method ကို အသုံးပြု၍ အချက်အလက်များ စိစစ်နိုင်သည်။ - -#### AJAX Requests & Validation -In this example, we used a traditional form to send data to the application. However, many applications use AJAX requests. When using the `validate` method during an AJAX request, Laravel will not generate a redirect response. Instead, Laravel generates a JSON response containing all of the validation errors. This JSON response will be sent with a 422 HTTP status code. + if ($validator->fails()) + { + // The given data did not pass validation + } - -## Form Request Validation +စိစစ်ခြင်း မအောင်မြင်ပါက validator မှ error message ကို ရယူနိုင်ပေသည်။ - -### Creating Form Requests + $messages = $validator->messages(); -For more complex validation scenarios, you may wish to create a "form request". Form requests are custom request classes that contain validation logic. To create a form request class, use the `make:request` Artisan CLI command: +်fail ဖြစ်သည့် rule များကိုသာ ရယူလိုပြီး message များ မပါဝင်စေလိုပါက `failed` method ကို အသုံးပြုနိုင်သည်။ - php artisan make:request StoreBlogPost + $failed = $validator->failed(); -The generated class will be placed in the `app/Http/Requests` directory. If this directory does not exist, it will be created when you run the `make:request` command. Let's add a few validation rules to the `rules` method: +#### Files များစိစစ်ခြင်း - /** - * Get the validation rules that apply to the request. - * - * @return array - */ - public function rules() - { - return [ - 'title' => 'required|unique:posts|max:255', - 'body' => 'required', - ]; - } +`Validator` class အနေဖြင့် `size` နှင့် `mimes` အပါအဝင် များမြောင်လှသော validation method များကို အထောက်အပံ့ပေးထားပြီး file များ validate ပြုလုပ်လိုပါက ထိုထဲ့သို ့ ထည့်သွင်းရန်သာ လိုပေမည်။ -So, how are the validation rules evaluated? All you need to do is type-hint the request on your controller method. The incoming form request is validated before the controller method is called, meaning you do not need to clutter your controller with any validation logic: - /** - * Store the incoming blog post. - * - * @param StoreBlogPost $request - * @return Response - */ - public function store(StoreBlogPost $request) - { - // The incoming request is valid... - } - -If validation fails, a redirect response will be generated to send the user back to their previous location. The errors will also be flashed to the session so they are available for display. If the request was an AJAX request, a HTTP response with a 422 status code will be returned to the user including a JSON representation of the validation errors. - - -### Authorizing Form Requests - -The form request class also contains an `authorize` method. Within this method, you may check if the authenticated user actually has the authority to update a given resource. For example, if a user is attempting to update a blog post comment, do they actually own that comment? For example: - - /** - * Determine if the user is authorized to make this request. - * - * @return bool - */ - public function authorize() - { - $comment = Comment::find($this->route('comment')); - - return $comment && $this->user()->can('update', $comment); - } - -Since all form requests extend the base Laravel request class, we may use the `user` method to access the currently authenticated user. Also note the call to the `route` method in the example above. This method grants you access to the URI parameters defined on the route being called, such as the `{comment}` parameter in the example below: - - Route::post('comment/{comment}'); - -If the `authorize` method returns `false`, a HTTP response with a 403 status code will automatically be returned and your controller method will not execute. - -If you plan to have authorization logic in another part of your application, simply return `true` from the `authorize` method: - - /** - * Determine if the user is authorized to make this request. - * - * @return bool - */ - public function authorize() - { - return true; - } - - -### Customizing The Error Format - -If you wish to customize the format of the validation errors that are flashed to the session when validation fails, override the `formatErrors` on your base request (`App\Http\Requests\Request`). Don't forget to import the `Illuminate\Contracts\Validation\Validator` class at the top of the file: - - /** - * {@inheritdoc} - */ - protected function formatErrors(Validator $validator) - { - return $validator->errors()->all(); - } - - -### Customizing The Error Messages - -You may customize the error messages used by the form request by overriding the `messages` method. This method should return an array of attribute / rule pairs and their corresponding error messages: - - /** - * Get the error messages for the defined validation rules. - * - * @return array - */ - public function messages() - { - return [ - 'title.required' => 'A title is required', - 'body.required' => 'A message is required', - ]; - } - - -## Manually Creating Validators - -If you do not want to use the `ValidatesRequests` trait's `validate` method, you may create a validator instance manually using the `Validator` [facade](/docs/{{version}}/facades). The `make` method on the facade generates a new validator instance: - - all(), [ - 'title' => 'required|unique:posts|max:255', - 'body' => 'required', - ]); - - if ($validator->fails()) { - return redirect('post/create') - ->withErrors($validator) - ->withInput(); - } - - // Store the blog post... - } - } - -The first argument passed to the `make` method is the data under validation. The second argument is the validation rules that should be applied to the data. - -After checking if the request passed validation, you may use the `withErrors` method to flash the error messages to the session. When using this method, the `$errors` variable will automatically be shared with your views after redirection, allowing you to easily display them back to the user. The `withErrors` method accepts a validator, a `MessageBag`, or a PHP `array`. - - -### Automatic Redirection - -If you would like to create a validator instance manually but still take advantage of the automatic redirection offered by the `ValidatesRequest` trait, you may call the `validate` method on an existing validator instance. If validation fails, the user will automatically be redirected or, in the case of an AJAX request, a JSON response will be returned: - - Validator::make($request->all(), [ - 'title' => 'required|unique:posts|max:255', - 'body' => 'required', - ])->validate(); - - -### Named Error Bags - -If you have multiple forms on a single page, you may wish to name the `MessageBag` of errors, allowing you to retrieve the error messages for a specific form. Simply pass a name as the second argument to `withErrors`: - - return redirect('register') - ->withErrors($validator, 'login'); - -You may then access the named `MessageBag` instance from the `$errors` variable: - - {{ $errors->login->first('email') }} - - -### After Validation Hook - -The validator also allows you to attach callbacks to be run after validation is completed. This allows you to easily perform further validation and even add more error messages to the message collection. To get started, use the `after` method on a validator instance: - - $validator = Validator::make(...); + +## Error Messages များနှင့် လှုပ်ရှားခြင်း - $validator->after(function($validator) { - if ($this->somethingElseIsInvalid()) { - $validator->errors()->add('field', 'Something is wrong with this field!'); - } - }); - if ($validator->fails()) { - // - } +After calling the on a +`Validator` instance မှ `messages` method ကို ခေါ်ပြီးပါက Error message များဖြင့် အလုပ်လုပ်ရာတွင် လွယ်ကူစေမည့် method များစွာပါဝင်မည့် `MessageBag` ပါဝင်မည် ဖြစ်သည်။ - -## Working With Error Messages +#### Field တစ်ခုမှ ပထမဆုံး Error Message ကို ထုတ်ယူခြင်း -After calling the `errors` method on a `Validator` instance, you will receive an `Illuminate\Support\MessageBag` instance, which has a variety of convenient methods for working with error messages. The `$errors` variable that is automatically made available to all views is also an instance of the `MessageBag` class. + echo $messages->first('email'); -#### Retrieving The First Error Message For A Field +#### Field တစ်ခုမှ Error Message များထုတ်ယူခြင်း -To retrieve the first error message for a given field, use the `first` method: + foreach ($messages->get('email') as $message) + { + // + } - $errors = $validator->errors(); +#### Field အားလုံးမှ Error Message များထုတ်ယူခြင်း - echo $errors->first('email'); + foreach ($messages->all() as $message) + { + // + } -#### Retrieving All Error Messages For A Field +#### Field တစ်ခုမှ message ရှိမရှိ စစ်ဆေးခြင်း -If you need to retrieve an array of all the messages for a given field, use the `get` method: + if ($messages->has('email')) + { + // + } - foreach ($errors->get('email') as $message) { - // - } +#### Error Message များအား Format ပြောင်း၍ ထုတ်ယူခြင်း -#### Retrieving All Error Messages For All Fields + echo $messages->first('email', '

    :message

    '); + +> **မှတ်ချက်:** ပုံမှန်အားဖြင့် messages များကို Bootstrap ဖြင့် အဆင်ပြေမည့် ပုံစံများအနေဖြင့် သတ်မှတ်ထားပါသည်။ -To retrieve an array of all messages for all fields, use the `all` method: +#### Error Messages များအား Format တစ်ခု သတ်မှတ်၍ ထုတ်ယူခြင်း - foreach ($errors->all() as $message) { - // - } + foreach ($messages->all('
  • :message
  • ') as $message) + { + // + } -#### Determining If Messages Exist For A Field + +## Error Message များနှင့် View များ -The `has` method may be used to determine if any error messages exist for a given field: +Validation ကို ဆောင်ရွက်ပြီးသည်နှင့် Error message များကို လွယ်လင့်တကူ ပြန်လည်ပြသနိုင်ရန် လိုအပ်ပေသည်။ ထိုလိုအပ်ချက်များကို Laravel မှ အဆင်ပြေလွယ်ကူစွာ ဖြည့်စွမ်းထားသည်။ အောက်ပါ route များကို ဥပမာ အနေဖြင့်ကြည့်ပါ။ - if ($errors->has('email')) { - // - } + Route::get('register', function() + { + return View::make('user.register'); + }); - -### Custom Error Messages + Route::post('register', function() + { + $rules = array(...); -If needed, you may use custom error messages for validation instead of the defaults. There are several ways to specify custom messages. First, you may pass the custom messages as the third argument to the `Validator::make` method: + $validator = Validator::make(Input::all(), $rules); - $messages = [ - 'required' => 'The :attribute field is required.', - ]; + if ($validator->fails()) + { + return Redirect::to('register')->withErrors($validator); + } + }); - $validator = Validator::make($input, $rules, $messages); + +Note that when စိစစ်ခြင်း မအောင်မြင်ပါက `Validator` instance ကို `withErrors` method ဖြင့် Error များကို passing ပေးလိုက်ပြီး Redirect ပြုလုပ်လိုက်သည် ကို တွေ ့ရပေမည်။ အဆိုပါ method ကို အသုံးပြုခြင်းဖြင့် error message များကို လွယ်လင့်တကူ ဖြတ်ကနဲ ပြသရာတွင် သုံးနိုင်ရင် next request ၏ Session ထဲတွင် ထည့်သွင်းထားပါသည်။ -In this example, the `:attribute` place-holder will be replaced by the actual name of the field under validation. You may also utilize other place-holders in validation messages. For example: +သို ့ပင်သော်ညား GET route နဲ ့ Error Message များကို အသေချည်နှောင်ထားရန် မလိုသည်ကို သတိပြုရမည်။ အဘယ်ကြောင့်ဆိုသော် Laravel သည် Session data များမှ Error များကို စစ်ဆေးပြီး view ဆီသို ့ အဆင်ပြေသည်နှင့် တပြိုင်နက် ပြသနိုင်ရန် ပြင်ဆင်ထားသည်ကို သတိပြုရမည်။ **ထိုကြောင့် အရေးကြီးသည့် အချက်မှာ`$errors` ဟုသည် variable မှာ သင့် view ၏ request တိုင်းတွင် ပြင်ဆင်ထားသောကြောင့် အမြဲတမ်း အဆင်သင့် ဖြစ်နေသည်ကို မှတ်ထားရန်လိုသည်။ `$errors` variable မှာ `MessageBag` ၏ instance ဖြစ်သည်။ - $messages = [ - 'same' => 'The :attribute and :other must match.', - 'size' => 'The :attribute must be exactly :size.', - 'between' => 'The :attribute must be between :min - :max.', - 'in' => 'The :attribute must be one of the following types: :values', - ]; +ထိုကြောင့် redirect ပြုလုပ်ပြီးနောက် `$errors` variable နှင့် သင့် view မှာ အလိုအလျောက် ချည်နှောင်ပြီးသား ဖြစ်ပေသည်။ -#### Specifying A Custom Message For A Given Attribute + first('email'); ?> -Sometimes you may wish to specify a custom error messages only for a specific field. You may do so using "dot" notation. Specify the attribute's name first, followed by the rule: +### အမည်ပေးထားသော Error Bag များ - $messages = [ - 'email.required' => 'We need to know your e-mail address!', - ]; +သင့်အနေဖြင့် Page တစ်ခုတည်းတွင် များပြားလှသော form များသည်ရှိသည် ဆိုပါစို ့။ ထိုအခါ သင့်အနေဖြင့် Error များ၏ `MessageBag` များကို ကွဲပြားခြားနား စေရန် အမည်နာမ ပေးလိုပေမည်။ ထိုအခါတွင် သင့်အနေဖြင့် `withErrors` ဟုသည့် method ၏ ဒုတိယ argument အနေဖြင့် မိမိပေးလိုသည့် အမည်ကို ထည့်သွင်းနိုင်သည်။ - -#### Specifying Custom Messages In Language Files + return Redirect::to('register')->withErrors($validator, 'login'); -In most cases, you will probably specify your custom messages in a language file instead of passing them directly to the `Validator`. To do so, add your messages to `custom` array in the `resources/lang/xx/validation.php` language file. +ထိုနောက် သင့်အနေဖြင့် `$errors` variable မှ `MessageBag` instance ကို အောက်ပါအတိုင်း ဆွဲထုတ်နိုင်သည်။ - 'custom' => [ - 'email' => [ - 'required' => 'We need to know your e-mail address!', - ], - ], + login->first('email'); ?> -## Available Validation Rules - -Below is a list of all available validation rules and their function: - - - -
    - -[Accepted](#rule-accepted) -[Active URL](#rule-active-url) -[After (Date)](#rule-after) -[Alpha](#rule-alpha) -[Alpha Dash](#rule-alpha-dash) -[Alpha Numeric](#rule-alpha-num) -[Array](#rule-array) -[Before (Date)](#rule-before) -[Between](#rule-between) -[Boolean](#rule-boolean) -[Confirmed](#rule-confirmed) -[Date](#rule-date) -[Date Format](#rule-date-format) -[Different](#rule-different) -[Digits](#rule-digits) -[Digits Between](#rule-digits-between) -[Dimensions (Image Files)](#rule-dimensions) -[Distinct](#rule-distinct) -[E-Mail](#rule-email) -[Exists (Database)](#rule-exists) -[File](#rule-file) -[Filled](#rule-filled) -[Image (File)](#rule-image) -[In](#rule-in) -[In Array](#rule-in-array) -[Integer](#rule-integer) -[IP Address](#rule-ip) -[JSON](#rule-json) -[Max](#rule-max) -[MIME Types](#rule-mimetypes) -[MIME Type By File Extension](#rule-mimes) -[Min](#rule-min) -[Nullable](#rule-nullable) -[Not In](#rule-not-in) -[Numeric](#rule-numeric) -[Present](#rule-present) -[Regular Expression](#rule-regex) -[Required](#rule-required) -[Required If](#rule-required-if) -[Required Unless](#rule-required-unless) -[Required With](#rule-required-with) -[Required With All](#rule-required-with-all) -[Required Without](#rule-required-without) -[Required Without All](#rule-required-without-all) -[Same](#rule-same) -[Size](#rule-size) -[String](#rule-string) -[Timezone](#rule-timezone) -[Unique (Database)](#rule-unique) -[URL](#rule-url) - -
    +## အသုံးပြုနိုင်သည့် စိစစ်ခြင်း Rule များ + +အောက်တွင် ဖော်ပြထားသည်မှာ အသုံးပြုနိုင်သော စိစစ်ရေး rule များနှင့် ၄င်းတို ့၏ function များဖြစ်ကြသည်။ + +- [Accepted](#rule-accepted) +- [Active URL](#rule-active-url) +- [After (Date)](#rule-after) +- [Alpha](#rule-alpha) +- [Alpha Dash](#rule-alpha-dash) +- [Alpha Numeric](#rule-alpha-num) +- [Array](#rule-array) +- [Before (Date)](#rule-before) +- [Between](#rule-between) +- [Confirmed](#rule-confirmed) +- [Date](#rule-date) +- [Date Format](#rule-date-format) +- [Different](#rule-different) +- [Digits](#rule-digits) +- [Digits Between](#rule-digits-between) +- [E-Mail](#rule-email) +- [Exists (Database)](#rule-exists) +- [Image (File)](#rule-image) +- [In](#rule-in) +- [Integer](#rule-integer) +- [IP Address](#rule-ip) +- [Max](#rule-max) +- [MIME Types](#rule-mimes) +- [Min](#rule-min) +- [Not In](#rule-not-in) +- [Numeric](#rule-numeric) +- [Regular Expression](#rule-regex) +- [Required](#rule-required) +- [Required If](#rule-required-if) +- [Required With](#rule-required-with) +- [Required With All](#rule-required-with-all) +- [Required Without](#rule-required-without) +- [Required Without All](#rule-required-without-all) +- [Same](#rule-same) +- [Size](#rule-size) +- [Unique (Database)](#rule-unique) +- [URL](#rule-url) #### accepted -The field under validation must be _yes_, _on_, _1_, or _true_. This is useful for validating "Terms of Service" acceptance. +အဆိုပါ field တွင် စိစစ်သည်မှာ _yes_, _on_, သို ့မဟုတ် _1_ တို ့ဖြစ်သည်။ "Terms of Service" ကဲ့သို ့ တခုသာ ရွေးမရွေး စိစစ်ရာနေရာများတွင် ၄င်းကို အသုံးပြုနိုင်သည်။ + #### active_url -The field under validation must be a valid URL according to the `checkdnsrr` PHP function. +အဆိုပါ field တွင် စိစစ်သည်မှာ `checkdnsrr` ဟုသည် PHP function ကို အသုံးပြု၍ အင်ထုထားသည့် URL ဟုတ်မဟုတ်ကို စစ်ဆေးသွားမည် ဖြစ်သည်။ #### after:_date_ -The field under validation must be a value after a given date. The dates will be passed into the `strtotime` PHP function: - - 'start_date' => 'required|date|after:tomorrow' - -Instead of passing a date string to be evaluated by `strtotime`, you may specify another field to compare against the date: - - 'finish_date' => 'required|date|after:start_date' +အဆိုပါ field တွင် စိစစ်သည်မှာ သတ်မှတ်ထားသော date အတွင်းတွင်သာ ထည့်သွင်းစေရန် ဖြစ်သည်။ date များကို PHP ၏ `strtotime` function ကို အသုံးပြု၍ ပြောင်းလဲကာ စိစစ်သွားမည် ဖြစ်သည်။ #### alpha - -The field under validation must be entirely alphabetic characters. +အဆိုပါ field တွင် ပါဝင်သော အချက်အလက်များသည် အက္ခရာ များသာ ဖြစ်ရမည် ဖြစ်သည်။ ဥပမာ ကိန်းဂဏန်းများကို လက်ခံသွားမည် မဟုတ်။ #### alpha_dash -The field under validation may have alpha-numeric characters, as well as dashes and underscores. +အဆိုပါ field တွင် ပါဝင်သော အချက်အလက်များသည် အက္ခရာ နှင့် ကိန်းဂဏန်းများသာ မက dash နှင့် underscore ကိုပါ လက်ခံသွားမည် ဖြစ်သည်။ #### alpha_num -The field under validation must be entirely alpha-numeric characters. +အဆိုပါ field တွင် ပါဝင်သော အချက်အလက်များသည် အက္ခရာ နှင့် ကိန်းဂဏန်းများသာ လက်ခံသွားမည်။ #### array -The field under validation must be a PHP `array`. +အဆိုပါ field တွင် ပါဝင်သော အချက်အလက်များသည် array အမျိုးအစားကိုသာ လက်ခံသွားမည်။ #### before:_date_ -The field under validation must be a value preceding the given date. The dates will be passed into the PHP `strtotime` function. +အဆိုပါ field တွင်ပါဝင်သော အချက်အလက်များကို date ဖြင့် စိစစ်သတ်မှတ်ခြင်း ဖြစ်သည်။ dates များကို PHP မှ `strtotime` function ကို အသုံးပြု၍ passing ပေးသွားမည် ဖြစ်သည်။ #### between:_min_,_max_ -The field under validation must have a size between the given _min_ and _max_. Strings, numerics, and files are evaluated in the same fashion as the [`size`](#rule-size) rule. - - -#### boolean - -The field under validation must be able to be cast as a boolean. Accepted input are `true`, `false`, `1`, `0`, `"1"`, and `"0"`. +အဆိုပါ field တွင်ထည့်သွင်းသော အချက်အလက်များ ၏ အများဆုံးနှင့် အနည်းဆုံး တန်ဖိုးများကို သတ်မှတ်ခြင်း ဖြစ်ပြီး String ၊ numeric နှင့် file များကို `size` rule ကို အသုံးပြုသကဲ့သို ့ ဆင်တင်တင်ပင် ဖြစ်သည်။ #### confirmed -The field under validation must have a matching field of `foo_confirmation`. For example, if the field under validation is `password`, a matching `password_confirmation` field must be present in the input. +အဆိုပါ field ၏ အချက်အလက်သည် ရည်ညွန်း field ၏ အချက်အလက် ဥပမာ `foo_confirmation` နှင့် တူညီရမည် ဖြစ်သည်။ ဥပမာ ပြုရသော် `password` field သည် `password_confirmation` field နှင့် ထပ်တူညီရမည် ဖြစ်သည်။ #### date -The field under validation must be a valid date according to the `strtotime` PHP function. +တိကျ မှန်ကန်သော date ဖြစ်စေရန် စိစစ်ပေးပြီး `strtotime` ဟူသော PHP function ကို အသုံးပြုထားသည်။ #### date_format:_format_ -The field under validation must match the given _format_. The format will be evaluated using the PHP `date_parse_from_format` function. You should use **either** `date` or `date_format` when validating a field, not both. +အဆိုပါ field မှ format နှင့် တူညီရမည် ဖြစ်ပြီး `date_parse_from_format` ဟူသည် PHP function ကို အသုံးပြုထားသည်။ #### different:_field_ -The field under validation must have a different value than _field_. +အဆိုပါ field သည် အခြား ရည်ညွန်း field နှင့် လုံးဝ ကွဲပြားခြားရမည် ဖြစ်သည်။ +The given _field_ must be different than the field under validation. #### digits:_value_ -The field under validation must be _numeric_ and must have an exact length of _value_. +အဆိုပါ file တွင် numeric value ဖြစ်ပြီး တိကျသေချာသော ဂဏန်း အလုံးအရေအတွက် ကိုသာ ထည့်သွင်းရမည်ဖြစ်သည်။ #### digits_between:_min_,_max_ -The field under validation must have a length between the given _min_ and _max_. - - -#### dimensions - -The file under validation must be an image meeting the dimension constraints as specified by the rule's parameters: - - 'avatar' => 'dimensions:min_width=100,min_height=200' - -Available constraints are: _min\_width_, _max\_width_, _min\_height_, _max\_height_, _width_, _height_, _ratio_. - -A _ratio_ constraint should be represented as width divided by height. This can be specified either by a statement like `3/2` or a float like `1.5`: - - 'avatar' => 'dimensions:ratio=3/2' - - -#### distinct - -When working with arrays, the field under validation must not have any duplicate values. - - 'foo.*.id' => 'distinct' +အဆို field တွင် _min_ and _max_ အကြား ထည့်သွင်းရသော ဂဏန်းအလုံးအရေအတွက်ကိုသာ ထည့်သွင်းခွင့်ရမည်ဖြစ်သည်။ #### email -The field under validation must be formatted as an e-mail address. +အဆိုပါ field တွင် email address format အတိုင်း ထည့်သွင်းထားခြင်း ရှိမရှိ စစ်ဆေးသွားမည် ဖြစ်သည်။ #### exists:_table_,_column_ @@ -638,83 +285,44 @@ The field under validation must exist on a given database table. #### Basic Usage Of Exists Rule - 'state' => 'exists:states' + 'state' => 'exists:states' #### Specifying A Custom Column Name - 'state' => 'exists:states,abbreviation' + 'state' => 'exists:states,abbreviation' You may also specify more conditions that will be added as "where" clauses to the query: - 'email' => 'exists:staff,email,account_id,1' - -These conditions may be negated using the `!` sign: - - 'email' => 'exists:staff,email,role,!admin' - -You may also pass `NULL` or `NOT_NULL` to the "where" clause: - - 'email' => 'exists:staff,email,deleted_at,NULL' + 'email' => 'exists:staff,email,account_id,1' - 'email' => 'exists:staff,email,deleted_at,NOT_NULL' +Passing `NULL` as a "where" clause value will add a check for a `NULL` database value: -Occasionally, you may need to specify a specific database connection to be used for the `exists` query. You can accomplish this by prepending the connection name to the table name using "dot" syntax: - - 'email' => 'exists:connection.staff,email' - - -#### file - -The field under validation must be a successfully uploaded file. - - -#### filled - -The field under validation must not be empty when it is present. + 'email' => 'exists:staff,email,deleted_at,NULL' #### image -The file under validation must be an image (jpeg, png, bmp, gif, or svg) +The file under validation must be an image (jpeg, png, bmp, or gif) #### in:_foo_,_bar_,... The field under validation must be included in the given list of values. - -#### in_array:_anotherfield_ - -The field under validation must exist in _anotherfield_'s values. - #### integer -The field under validation must be an integer. +The field under validation must have an integer value. #### ip -The field under validation must be an IP address. - - -#### json - -The field under validation must be a valid JSON string. +The field under validation must be formatted as an IP address. #### max:_value_ -The field under validation must be less than or equal to a maximum _value_. Strings, numerics, and files are evaluated in the same fashion as the [`size`](#rule-size) rule. - - -#### mimetypes:_text/plain_,... - -The file under validation must match one of the given MIME types: - - 'video' => 'mimetypes:video/avi,video/mpeg,video/quicktime' - -To determine the MIME type of the uploaded file, the file's contents will be read and the framework will attempt to guess the MIME type, which may be different from the client provided MIME type. +The field under validation must be less than or equal to a maximum _value_. Strings, numerics, and files are evaluated in the same fashion as the `size` rule. #### mimes:_foo_,_bar_,... @@ -723,21 +331,12 @@ The file under validation must have a MIME type corresponding to one of the list #### Basic Usage Of MIME Rule - 'photo' => 'mimes:jpeg,bmp,png' - -Even though you only need to specify the extensions, this rule actually validates against the MIME type of the file by reading the file's contents and guessing its MIME type. - -A full listing of MIME types and their corresponding extensions may be found at the following location: [http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types](http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types) + 'photo' => 'mimes:jpeg,bmp,png' #### min:_value_ -The field under validation must have a minimum _value_. Strings, numerics, and files are evaluated in the same fashion as the [`size`](#rule-size) rule. - - -#### nullable - -The field under validation may be `null`. This is particularly useful when validating primitive such as strings and integers that can contain `null` values. +The field under validation must have a minimum _value_. Strings, numerics, and files are evaluated in the same fashion as the `size` rule. #### not_in:_foo_,_bar_,... @@ -747,12 +346,7 @@ The field under validation must not be included in the given list of values. #### numeric -The field under validation must be numeric. - - -#### present - -The field under validation must be present in the input data but can be empty. +The field under validation must have a numeric value. #### regex:_pattern_ @@ -764,46 +358,32 @@ The field under validation must match the given regular expression. #### required -The field under validation must be present in the input data and not empty. A field is considered "empty" if one of the following conditions are true: - -
    - -- The value is `null`. -- The value is an empty string. -- The value is an empty array or empty `Countable` object. -- The value is an uploaded file with no path. - -
    +The field under validation must be present in the input data. -#### required_if:_anotherfield_,_value_,... +#### required\_if:_field_,_value_ -The field under validation must be present and not empty if the _anotherfield_ field is equal to any _value_. - - -#### required_unless:_anotherfield_,_value_,... - -The field under validation must be present and not empty unless the _anotherfield_ field is equal to any _value_. +The field under validation must be present if the _field_ field is equal to _value_. #### required_with:_foo_,_bar_,... -The field under validation must be present and not empty _only if_ any of the other specified fields are present. +The field under validation must be present _only if_ any of the other specified fields are present. #### required_with_all:_foo_,_bar_,... -The field under validation must be present and not empty _only if_ all of the other specified fields are present. +The field under validation must be present _only if_ all of the other specified fields are present. #### required_without:_foo_,_bar_,... -The field under validation must be present and not empty _only when_ any of the other specified fields are not present. +The field under validation must be present _only when_ any of the other specified fields are not present. #### required_without_all:_foo_,_bar_,... -The field under validation must be present and not empty _only when_ all of the other specified fields are not present. +The field under validation must be present _only when_ the all of the other specified fields are not present. #### same:_field_ @@ -813,193 +393,173 @@ The given _field_ must match the field under validation. #### size:_value_ -The field under validation must have a size matching the given _value_. For string data, _value_ corresponds to the number of characters. For numeric data, _value_ corresponds to a given integer value. For an array, _size_ corresponds to the `count` of the array. For files, _size_ corresponds to the file size in kilobytes. - - -#### string - -The field under validation must be a string. If you would like to allow the field to also be `null`, you should assign the `nullable` rule to the field. - - -#### timezone - -The field under validation must be a valid timezone identifier according to the `timezone_identifiers_list` PHP function. +The field under validation must have a size matching the given _value_. For string data, _value_ corresponds to the number of characters. For numeric data, _value_ corresponds to a given integer value. For files, _size_ corresponds to the file size in kilobytes. #### unique:_table_,_column_,_except_,_idColumn_ -The field under validation must be unique in a given database table. If the `column` option is not specified, the field name will be used. - -**Specifying A Custom Column Name:** - - 'email' => 'unique:users,email_address' +The field under validation must be unique on a given database table. If the `column` option is not specified, the field name will be used. -**Custom Database Connection** +#### Basic Usage Of Unique Rule -Occasionally, you may need to set a custom connection for database queries made by the Validator. As seen above, setting `unique:users` as a validation rule will use the default database connection to query the database. To override this, specify the connection and the table name using "dot" syntax: + 'email' => 'unique:users' - 'email' => 'unique:connection.users,email_address' - -**Forcing A Unique Rule To Ignore A Given ID:** - -Sometimes, you may wish to ignore a given ID during the unique check. For example, consider an "update profile" screen that includes the user's name, e-mail address, and location. Of course, you will want to verify that the e-mail address is unique. However, if the user only changes the name field and not the e-mail field, you do not want a validation error to be thrown because the user is already the owner of the e-mail address. To tell the unique rule to ignore the user's ID, you may pass the ID as the third parameter: +#### Specifying A Custom Column Name - 'email' => 'unique:users,email_address,'.$user->id + 'email' => 'unique:users,email_address' -If your table uses a primary key column name other than `id`, you may specify it as the fourth parameter: +#### Forcing A Unique Rule To Ignore A Given ID - 'email' => 'unique:users,email_address,'.$user->id.',user_id' + 'email' => 'unique:users,email_address,10' -**Adding Additional Where Clauses:** +#### Adding Additional Where Clauses You may also specify more conditions that will be added as "where" clauses to the query: - 'email' => 'unique:users,email_address,NULL,id,account_id,1' + 'email' => 'unique:users,email_address,NULL,id,account_id,1' In the rule above, only rows with an `account_id` of `1` would be included in the unique check. #### url -The field under validation must be a valid URL. +The field under validation must be formatted as an URL. + +> **Note:** This function uses PHP's `filter_var` method. ## Conditionally Adding Rules -#### Validating When Present - In some situations, you may wish to run validation checks against a field **only** if that field is present in the input array. To quickly accomplish this, add the `sometimes` rule to your rule list: - $v = Validator::make($data, [ - 'email' => 'sometimes|required|email', - ]); + $v = Validator::make($data, array( + 'email' => 'sometimes|required|email', + )); In the example above, the `email` field will only be validated if it is present in the `$data` array. #### Complex Conditional Validation -Sometimes you may wish to add validation rules based on more complex conditional logic. For example, you may wish to require a given field only if another field has a greater value than 100. Or, you may need two fields to have a given value only when another field is present. Adding these validation rules doesn't have to be a pain. First, create a `Validator` instance with your _static rules_ that never change: +Sometimes you may wish to require a given field only if another field has a greater value than 100. Or you may need two fields to have a given value only when another field is present. Adding these validation rules doesn't have to be a pain. First, create a `Validator` instance with your _static rules_ that never change: - $v = Validator::make($data, [ - 'email' => 'required|email', - 'games' => 'required|numeric', - ]); + $v = Validator::make($data, array( + 'email' => 'required|email', + 'games' => 'required|numeric', + )); -Let's assume our web application is for game collectors. If a game collector registers with our application and they own more than 100 games, we want them to explain why they own so many games. For example, perhaps they run a game resale shop, or maybe they just enjoy collecting. To conditionally add this requirement, we can use the `sometimes` method on the `Validator` instance. +Let's assume our web application is for game collectors. If a game collector registers with our application and they own more than 100 games, we want them to explain why they own so many games. For example, perhaps they run a game re-sell shop, or maybe they just enjoy collecting. To conditionally add this requirement, we can use the `sometimes` method on the `Validator` instance. - $v->sometimes('reason', 'required|max:500', function($input) { - return $input->games >= 100; - }); + $v->sometimes('reason', 'required|max:500', function($input) + { + return $input->games >= 100; + }); The first argument passed to the `sometimes` method is the name of the field we are conditionally validating. The second argument is the rules we want to add. If the `Closure` passed as the third argument returns `true`, the rules will be added. This method makes it a breeze to build complex conditional validations. You may even add conditional validations for several fields at once: - $v->sometimes(['reason', 'cost'], 'required', function($input) { - return $input->games >= 100; - }); + $v->sometimes(array('reason', 'cost'), 'required', function($input) + { + return $input->games >= 100; + }); + +> **Note:** The `$input` parameter passed to your `Closure` will be an instance of `Illuminate\Support\Fluent` and may be used as an object to access your input and files. + + +## Custom Error Messages + +If needed, you may use custom error messages for validation instead of the defaults. There are several ways to specify custom messages. -> {tip} The `$input` parameter passed to your `Closure` will be an instance of `Illuminate\Support\Fluent` and may be used to access your input and files. +#### Passing Custom Messages Into Validator - -## Validating Arrays + $messages = array( + 'required' => 'The :attribute field is required.', + ); -Validating array based form input fields doesn't have to be a pain. For example, to validate that each e-mail in a given array input field is unique, you may do the following: + $validator = Validator::make($input, $rules, $messages); - $validator = Validator::make($request->all(), [ - 'person.*.email' => 'email|unique:users', - 'person.*.first_name' => 'required_with:person.*.last_name', - ]); +> *Note:* The `:attribute` place-holder will be replaced by the actual name of the field under validation. You may also utilize other place-holders in validation messages. + +#### Other Validation Place-Holders + + $messages = array( + 'same' => 'The :attribute and :other must match.', + 'size' => 'The :attribute must be exactly :size.', + 'between' => 'The :attribute must be between :min - :max.', + 'in' => 'The :attribute must be one of the following types: :values', + ); + +#### Specifying A Custom Message For A Given Attribute -Likewise, you may use the `*` character when specifying your validation messages in your language files, making it a breeze to use a single validation message for array based fields: +Sometimes you may wish to specify a custom error messages only for a specific field: - 'custom' => [ - 'person.*.email' => [ - 'unique' => 'Each person must have a unique e-mail address', - ] - ], + $messages = array( + 'email.required' => 'We need to know your e-mail address!', + ); + + +#### Specifying Custom Messages In Language Files + +In some cases, you may wish to specify your custom messages in a language file instead of passing them directly to the `Validator`. To do so, add your messages to `custom` array in the `app/lang/xx/validation.php` language file. + + 'custom' => array( + 'email' => array( + 'required' => 'We need to know your e-mail address!', + ), + ), ## Custom Validation Rules -Laravel provides a variety of helpful validation rules; however, you may wish to specify some of your own. One method of registering custom validation rules is using the `extend` method on the `Validator` [facade](/docs/{{version}}/facades). Let's use this method within a [service provider](/docs/{{version}}/providers) to register a custom validation rule: - - "Your input was invalid!", +Note that you will also need to define an error message for your custom rules. You can do so either using an inline custom message array or by adding an entry in the validation language file. - "accepted" => "The :attribute must be accepted.", +#### Extending The Validator Class - // The rest of the validation error messages... +Instead of using Closure callbacks to extend the Validator, you may also extend the Validator class itself. To do so, write a Validator class that extends `Illuminate\Validation\Validator`. You may add validation methods to the class by prefixing them with `validate`: -When creating a custom validation rule, you may sometimes need to define custom place-holder replacements for error messages. You may do so by creating a custom Validator as described above then making a call to the `replacer` method on the `Validator` facade. You may do this within the `boot` method of a [service provider](/docs/{{version}}/providers): + 'unique']; +Next, you need to register your custom Validator extension: - $input = ['name' => null]; + Validator::resolver(function($translator, $data, $rules, $messages) + { + return new CustomValidator($translator, $data, $rules, $messages); + }); - Validator::make($input, $rules)->passes(); // true +When creating a custom validation rule, you may sometimes need to define custom place-holder replacements for error messages. You may do so by creating a custom Validator as described above, and adding a `replaceXXX` function to the validator. -For a rule to run even when an attribute is empty, the rule must imply that the attribute is required. To create such an "implicit" extension, use the `Validator::extendImplicit()` method: + protected function replaceFoo($message, $attribute, $rule, $parameters) + { + return str_replace(':foo', $parameters[0], $message); + } - Validator::extendImplicit('foo', function($attribute, $value, $parameters, $validator) { - return $value == 'foo'; - }); +If you would like to add a custom message "replacer" without extending the `Validator` class, you may use the `Validator::replacer` method: -> {note} An "implicit" extension only _implies_ that the attribute is required. Whether it actually invalidates a missing or empty attribute is up to you. + Validator::replacer('rule', function($message, $attribute, $rule, $parameters) + { + // + }); \ No newline at end of file diff --git a/views.md b/views.md deleted file mode 100644 index 6e7b177..0000000 --- a/views.md +++ /dev/null @@ -1,200 +0,0 @@ -# Views - -- [Creating Views](#creating-views) -- [Passing Data To Views](#passing-data-to-views) - - [Sharing Data With All Views](#sharing-data-with-all-views) -- [View Composers](#view-composers) - - -## Creating Views - -Views contain the HTML served by your application and separate your controller / application logic from your presentation logic. Views are stored in the `resources/views` directory. A simple view might look something like this: - - - - - -

    Hello, {{ $name }}

    - - - -Since this view is stored at `resources/views/greeting.php`, we may return it using the global `view` helper like so: - - Route::get('/', function () { - return view('greeting', ['name' => 'James']); - }); - -As you can see, the first argument passed to the `view` helper corresponds to the name of the view file in the `resources/views` directory. The second argument is an array of data that should be made available to the view. In this case, we are passing the `name` variable, which is displayed in the view using [Blade syntax](/docs/{{version}}/blade). - -Of course, views may also be nested within sub-directories of the `resources/views` directory. "Dot" notation may be used to reference nested views. For example, if your view is stored at `resources/views/admin/profile.php`, you may reference it like so: - - return view('admin.profile', $data); - -#### Determining If A View Exists - -If you need to determine if a view exists, you may use the `View` facade. The `exists` method will return `true` if the view exists: - - use Illuminate\Support\Facades\View; - - if (View::exists('emails.customer')) { - // - } - - -## Passing Data To Views - -As you saw in the previous examples, you may pass an array of data to views: - - return view('greetings', ['name' => 'Victoria']); - -When passing information in this manner, `$data` should be an array with key/value pairs. Inside your view, you can then access each value using its corresponding key, such as ``. As an alternative to passing a complete array of data to the `view` helper function, you may use the `with` method to add individual pieces of data to the view: - - return view('greeting')->with('name', 'Victoria'); - - -#### Sharing Data With All Views - -Occasionally, you may need to share a piece of data with all views that are rendered by your application. You may do so using the view facade's `share` method. Typically, you should place calls to `share` within a service provider's `boot` method. You are free to add them to the `AppServiceProvider` or generate a separate service provider to house them: - - -## View Composers - -View composers are callbacks or class methods that are called when a view is rendered. If you have data that you want to be bound to a view each time that view is rendered, a view composer can help you organize that logic into a single location. - -For this example, let's register the view composers within a [service provider](/docs/{{version}}/providers). We'll use the `View` facade to access the underlying `Illuminate\Contracts\View\Factory` contract implementation. Remember, Laravel does not include a default directory for view composers. You are free to organize them however you wish. For example, you could create an `App\Http\ViewComposers` directory: - - {note} Remember, if you create a new service provider to contain your view composer registrations, you will need to add the service provider to the `providers` array in the `config/app.php` configuration file. - -Now that we have registered the composer, the `ProfileComposer@compose` method will be executed each time the `profile` view is being rendered. So, let's define the composer class: - - users = $users; - } - - /** - * Bind data to the view. - * - * @param View $view - * @return void - */ - public function compose(View $view) - { - $view->with('count', $this->users->count()); - } - } - -Just before the view is rendered, the composer's `compose` method is called with the `Illuminate\View\View` instance. You may use the `with` method to bind data to the view. - -> {tip} All view composers are resolved via the [service container](/docs/{{version}}/container), so you may type-hint any dependencies you need within a composer's constructor. - -#### Attaching A Composer To Multiple Views - -You may attach a view composer to multiple views at once by passing an array of views as the first argument to the `composer` method: - - View::composer( - ['profile', 'dashboard'], - 'App\Http\ViewComposers\MyViewComposer' - ); - -The `composer` method also accepts the `*` character as a wildcard, allowing you to attach a composer to all views: - - View::composer('*', function ($view) { - // - }); - -#### View Creators - -View **creators** are very similar to view composers; however, they are executed immediately after the view is instantiated instead of waiting until the view is about to render. To register a view creator, use the `creator` method: - - View::creator('profile', 'App\Http\ViewCreators\ProfileCreator'); From fadc2c300948e11951fd79f9adf20fae443bc125 Mon Sep 17 00:00:00 2001 From: Set Kyar Wa Lar Date: Sat, 4 Feb 2017 12:38:46 +0630 Subject: [PATCH 3/5] initial 5.4 commit --- apis.md | 0 artisan.md | 443 ++++++++++- authentication.md | 535 +++++++++++++ authorization.md | 327 ++++++++ billing.md | 654 ++++++++++++--- blade.md | 428 ++++++++++ broadcasting.md | 524 ++++++++++++ cache.md | 366 +++++++-- collections.md | 1477 ++++++++++++++++++++++++++++++++++ commands.md | 142 ---- configuration.md | 158 ++-- container.md | 249 ++++++ contracts.md | 205 +++++ contributing.md | 18 +- contributions.md | 85 ++ controllers.md | 369 +++++---- csrf.md | 69 ++ database-testing.md | 226 ++++++ database.md | 256 ++++-- documentation.md | 121 +-- dusk.md | 584 ++++++++++++++ eloquent-collections.md | 146 ++++ eloquent-mutators.md | 210 +++++ eloquent-relationships.md | 923 ++++++++++++++++++++++ eloquent-serialization.md | 147 ++++ eloquent.md | 1573 ++++++++++++++----------------------- encryption.md | 71 ++ envoy.md | 180 +++++ errors.md | 210 +++-- events.md | 403 +++++++--- extending.md | 223 ------ facades.md | 252 +++--- filesystem.md | 367 +++++++++ frontend.md | 72 ++ hashing.md | 58 ++ helpers.md | 1025 +++++++++++++++++++----- homestead.md | 335 ++++++-- html.md | 197 ----- http-tests.md | 145 ++++ installation.md | 131 +-- introduction.md | 25 - ioc.md | 186 ----- license.md | 2 +- lifecycle.md | 84 +- localization.md | 157 ++-- mail.md | 543 +++++++++++-- middleware.md | 250 ++++++ migrations.md | 442 +++++++++-- mix.md | 209 +++++ mocking.md | 260 ++++++ notifications.md | 851 ++++++++++++++++++++ packages.md | 458 ++++++----- pagination.md | 210 +++-- passport.md | 659 ++++++++++++++++ passwords.md | 97 +++ providers.md | 160 ++++ queries.md | 632 ++++++++++----- queues.md | 657 ++++++++++++---- quick.md | 178 ----- readme.md | 16 +- redirects.md | 88 +++ redis.md | 244 ++++-- releases.md | 1063 ++++++++++++++++++++++++- requests.md | 358 +++++---- responses.md | 315 ++++---- routing.md | 476 +++++------ scheduling.md | 222 ++++++ schema.md | 216 ----- scout.md | 303 +++++++ security.md | 310 -------- seeding.md | 94 +++ session.md | 286 +++++-- ssh.md | 263 ------- structure.md | 160 ++++ summary.md | 47 -- templates.md | 180 ----- testing.md | 233 +----- upgrade.md | 483 +++++++++--- valet.md | 232 ++++++ validation.md | 1093 +++++++++++++++++++------- views.md | 200 +++++ 81 files changed, 20516 insertions(+), 6330 deletions(-) create mode 100644 apis.md create mode 100644 authentication.md create mode 100644 authorization.md create mode 100644 blade.md create mode 100644 broadcasting.md create mode 100644 collections.md delete mode 100644 commands.md create mode 100644 container.md create mode 100644 contracts.md create mode 100644 contributions.md create mode 100644 csrf.md create mode 100644 database-testing.md create mode 100644 dusk.md create mode 100644 eloquent-collections.md create mode 100644 eloquent-mutators.md create mode 100644 eloquent-relationships.md create mode 100644 eloquent-serialization.md create mode 100644 encryption.md create mode 100644 envoy.md delete mode 100644 extending.md create mode 100644 filesystem.md create mode 100644 frontend.md create mode 100644 hashing.md delete mode 100644 html.md create mode 100644 http-tests.md delete mode 100644 introduction.md delete mode 100644 ioc.md mode change 100755 => 100644 lifecycle.md mode change 100755 => 100644 localization.md mode change 100755 => 100644 mail.md create mode 100644 middleware.md mode change 100755 => 100644 migrations.md create mode 100644 mix.md create mode 100644 mocking.md create mode 100644 notifications.md mode change 100755 => 100644 packages.md mode change 100755 => 100644 pagination.md create mode 100644 passport.md create mode 100644 passwords.md create mode 100644 providers.md mode change 100755 => 100644 queries.md mode change 100755 => 100644 queues.md delete mode 100755 quick.md mode change 100755 => 100644 readme.md create mode 100644 redirects.md mode change 100755 => 100644 redis.md mode change 100755 => 100644 releases.md mode change 100755 => 100644 requests.md mode change 100755 => 100644 responses.md mode change 100755 => 100644 routing.md create mode 100644 scheduling.md delete mode 100755 schema.md create mode 100644 scout.md delete mode 100755 security.md create mode 100644 seeding.md mode change 100755 => 100644 session.md delete mode 100755 ssh.md create mode 100644 structure.md delete mode 100755 summary.md delete mode 100755 templates.md mode change 100755 => 100644 testing.md mode change 100755 => 100644 upgrade.md create mode 100644 valet.md mode change 100755 => 100644 validation.md create mode 100644 views.md diff --git a/apis.md b/apis.md new file mode 100644 index 0000000..e69de29 diff --git a/artisan.md b/artisan.md index e5712f4..1afe87d 100644 --- a/artisan.md +++ b/artisan.md @@ -1,39 +1,442 @@ -## Artisan CLI +# Artisan Console -- [မိတ်ဆက်](#introduction) -- [အသုုံးပြုပုုံ](#အသုုံးပြုပုုံ) +- [Introduction](#introduction) +- [Writing Commands](#writing-commands) + - [Generating Commands](#generating-commands) + - [Command Structure](#command-structure) + - [Closure Commands](#closure-commands) +- [Defining Input Expectations](#defining-input-expectations) + - [Arguments](#arguments) + - [Options](#options) + - [Input Arrays](#input-arrays) + - [Input Descriptions](#input-descriptions) +- [Command I/O](#command-io) + - [Retrieving Input](#retrieving-input) + - [Prompting For Input](#prompting-for-input) + - [Writing Output](#writing-output) +- [Registering Commands](#registering-commands) +- [Programmatically Executing Commands](#programmatically-executing-commands) + - [Calling Commands From Other Commands](#calling-commands-from-other-commands) -## မိတ်ဆက် +## Introduction -Artisan သည် laravel တွင်အသုုံးပြုသည့် command line interface တစ်ခုုဖြစ်သည်။ ၄င်းတွင် application develop ပြုလုုပ်ရာတွင် အလွန်အသုုံးဝင်လှသော commands များစွာပါဝင်သည်။ ၄င်းမှာ Symfony ၏ console component မှဆင်းသက်လာခြင်း ဖြစ်သည်။ +Artisan is the command-line interface included with Laravel. It provides a number of helpful commands that can assist you while you build your application. To view a list of all available Artisan commands, you may use the `list` command: + php artisan list - -## အသုုံးပြုပုုံ +Every command also includes a "help" screen which displays and describes the command's available arguments and options. To view a help screen, simply precede the name of the command with `help`: -#### အသုုံးပြုနုုိင်သည့် Command များကုုိ စီရီပြသခြင်း + php artisan help migrate -Artisan တွင်ပါဝင်သည့် Command အကုုန်လုုံးကုုိ list အနေဖြင့် ပြသလုုိပါက `list` ဟုုသည့် command ကုုိ အသုုံးပြုနုုိင်သည်။ +#### Laravel REPL - php artisan list +All Laravel applications include Tinker, a REPL powered by the [PsySH](https://github.com/bobthecow/psysh) package. Tinker allows you to interact with your entire Laravel application on the command line, including the Eloquent ORM, jobs, events, and more. To enter the Tinker environment, run the `tinker` Artisan command: -#### Command တစ်ခုုချင်း၏ အသုုံးပြုခြင်း လမ်းညွန်မှုကုုိ ကြည့်ရှုခြင်း + php artisan tinker -Command တုုိင်းလုုိလုုိ တွင် “help” ဟုု အပုုိဆောင်း ရုုိက်ခြင်း ဖြင့် မိမိတုုိ ့ အသုုံးပြုမည့် Command တွင် ထည့်သွင်းရမည့် arguments များနှင့် ရွေးချယ်စရာများကုုိ သိရှိနုုိင်ပါသည်။ + +## Writing Commands - php artisan help migrate +In addition to the commands provided with Artisan, you may also build your own custom commands. Commands are typically stored in the `app/Console/Commands` directory; however, you are free to choose your own storage location as long as your commands can be loaded by Composer. -#### Configuration Environment ကုုိ သတ်မှတ်ခြင်း + +### Generating Commands -မိမိတုုိ ့ အသုုံးပြုလုုိသည် Configuration Environment ကုုိ —env ဟုုသော switch ဖြင့် ရွေးချယ်သတ်မှတ်နုုိင်သည်။ +To create a new command, use the `make:command` Artisan command. This command will create a new command class in the `app/Console/Commands` directory. Don't worry if this directory does not exist in your application, since it will be created the first time you run the `make:command` Artisan command. The generated command will include the default set of properties and methods that are present on all commands: + php artisan make:command SendEmails - php artisan migrate --env=local +Next, you will need to [register the command](#registering-commands) before it can be executed via the Artisan CLI. -#### လက်ရှိ အသုုံးပြုနေသည့် Laravel version ကိုုဖော်ပြခြင်း + +### Command Structure -မိမိတုုိ ့လက်ရှိအသုုံးပြုနေသည့် Laravel version ကုုိ သိရှိလုုိပါက —switch ကုုိ အသုုံးပြုပြီး သိရှိနုုိင်ပါသည်။ - +After generating your command, you should fill in the `signature` and `description` properties of the class, which will be used when displaying your command on the `list` screen. The `handle` method will be called when your command is executed. You may place your command logic in this method. - php artisan --version +> {tip} For greater code reuse, it is good practice to keep your console commands light and let them defer to application services to accomplish their tasks. In the example below, note that we inject a service class to do the "heavy lifting" of sending the e-mails. + +Let's take a look at an example command. Note that we are able to inject any dependencies we need into the command's constructor. The Laravel [service container](/docs/{{version}}/container) will automatically inject all dependencies type-hinted in the constructor: + + drip = $drip; + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function handle() + { + $this->drip->send(User::find($this->argument('user'))); + } + } + + +### Closure Commands + +Closure based commands provide an alternative to defining console commands as classes. In the same way that route Closures are an alternative to controllers, think of command Closures as an alternative to command classes. Within the `commands` method of your `app/Console/Kernel.php` file, Laravel loads the `routes/console.php` file: + + /** + * Register the Closure based commands for the application. + * + * @return void + */ + protected function commands() + { + require base_path('routes/console.php'); + } + +Even though this file does not define HTTP routes, it defines console based entry points (routes) into your application. Within this file, you may define all of your Closure based routes using the `Artisan::command` method. The `command` method accepts two arguments: the [command signature](#defining-input-expectations) and a Closure which receives the commands arguments and options: + + Artisan::command('build {project}', function ($project) { + $this->info("Building {$project}!"); + }); + +The Closure is bound to the underlying command instance, so you have full access to all of the helper methods you would typically be able to access on a full command class. + +#### Type-Hinting Dependencies + +In addition to receiving your command's arguments and options, command Closures may also type-hint additional dependencies that you would like resolved out of the [service container](/docs/{{version}}/container): + + use App\User; + use App\DripEmailer; + + Artisan::command('email:send {user}', function (DripEmailer $drip, $user) { + $drip->send(User::find($user)); + }); + +#### Closure Command Descriptions + +When defining a Closure based command, you may use the `describe` method to add a description to the command. This description will be displayed when you run the `php artisan list` or `php artisan help` commands: + + Artisan::command('build {project}', function ($project) { + $this->info("Building {$project}!"); + })->describe('Build the project'); + + +## Defining Input Expectations + +When writing console commands, it is common to gather input from the user through arguments or options. Laravel makes it very convenient to define the input you expect from the user using the `signature` property on your commands. The `signature` property allows you to define the name, arguments, and options for the command in a single, expressive, route-like syntax. + + +### Arguments + +All user supplied arguments and options are wrapped in curly braces. In the following example, the command defines one **required** argument: `user`: + + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'email:send {user}'; + +You may also make arguments optional and define default values for arguments: + + // Optional argument... + email:send {user?} + + // Optional argument with default value... + email:send {user=foo} + + +### Options + +Options, like arguments, are another form of user input. Options are prefixed by two hyphens (`--`) when they are specified on the command line. There are two types of options: those that receive a value and those that don't. Options that don't receive a value serve as a boolean "switch". Let's take a look at an example of this type of option: + + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'email:send {user} {--queue}'; + +In this example, the `--queue` switch may be specified when calling the Artisan command. If the `--queue` switch is passed, the value of the option will be `true`. Otherwise, the value will be `false`: + + php artisan email:send 1 --queue + + +#### Options With Values + +Next, let's take a look at an option that expects a value. If the user must specify a value for an option, suffix the option name with a `=` sign: + + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'email:send {user} {--queue=}'; + +In this example, the user may pass a value for the option like so: + + php artisan email:send 1 --queue=default + +You may assign default values to options by specifying the default value after the option name. If no option value is passed by the user, the default value will be used: + + email:send {user} {--queue=default} + + +#### Option Shortcuts + +To assign a shortcut when defining an option, you may specify it before the option name and use a | delimiter to separate the shortcut from the full option name: + + email:send {user} {--Q|queue} + + +### Input Arrays + +If you would like to define arguments or options to expect array inputs, you may use the `*` character. First, let's take a look at an example that specifies an array argument: + + email:send {user*} + +When calling this method, the `user` arguments may be passed in order to the command line. For example, the following command will set the value of `user` to `['foo', 'bar']`: + + php artisan email:send foo bar + +When defining an option that expects an array input, each option value passed to the command should be prefixed with the option name: + + email:send {user} {--id=*} + + php artisan email:send --id=1 --id=2 + + +### Input Descriptions + +You may assign descriptions to input arguments and options by separating the parameter from the description using a colon. If you need a little extra room to define your command, feel free to spread the definition across multiple lines: + + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'email:send + {user : The ID of the user} + {--queue= : Whether the job should be queued}'; + + +## Command I/O + + +### Retrieving Input + +While your command is executing, you will obviously need to access the values for the arguments and options accepted by your command. To do so, you may use the `argument` and `option` methods: + + /** + * Execute the console command. + * + * @return mixed + */ + public function handle() + { + $userId = $this->argument('user'); + + // + } + +If you need to retrieve all of the arguments as an `array`, call the `arguments` method: + + $arguments = $this->arguments(); + +Options may be retrieved just as easily as arguments using the `option` method. To retrieve all of the options as an array, call the `options` method: + + // Retrieve a specific option... + $queueName = $this->option('queue'); + + // Retrieve all options... + $options = $this->options(); + +If the argument or option does not exist, `null` will be returned. + + +### Prompting For Input + +In addition to displaying output, you may also ask the user to provide input during the execution of your command. The `ask` method will prompt the user with the given question, accept their input, and then return the user's input back to your command: + + /** + * Execute the console command. + * + * @return mixed + */ + public function handle() + { + $name = $this->ask('What is your name?'); + } + +The `secret` method is similar to `ask`, but the user's input will not be visible to them as they type in the console. This method is useful when asking for sensitive information such as a password: + + $password = $this->secret('What is the password?'); + +#### Asking For Confirmation + +If you need to ask the user for a simple confirmation, you may use the `confirm` method. By default, this method will return `false`. However, if the user enters `y` or `yes` in response to the prompt, the method will return `true`. + + if ($this->confirm('Do you wish to continue?')) { + // + } + +#### Auto-Completion + +The `anticipate` method can be used to provide auto-completion for possible choices. The user can still choose any answer, regardless of the auto-completion hints: + + $name = $this->anticipate('What is your name?', ['Taylor', 'Dayle']); + +#### Multiple Choice Questions + +If you need to give the user a predefined set of choices, you may use the `choice` method. You may set the default value to be returned if no option is chosen: + + $name = $this->choice('What is your name?', ['Taylor', 'Dayle'], $default); + + +### Writing Output + +To send output to the console, use the `line`, `info`, `comment`, `question` and `error` methods. Each of these methods will use appropriate ANSI colors for their purpose. For example, let's display some general information to the user. Typically, the `info` method will display in the console as green text: + + /** + * Execute the console command. + * + * @return mixed + */ + public function handle() + { + $this->info('Display this on the screen'); + } + +To display an error message, use the `error` method. Error message text is typically displayed in red: + + $this->error('Something went wrong!'); + +If you would like to display plain, uncolored console output, use the `line` method: + + $this->line('Display this on the screen'); + +#### Table Layouts + +The `table` method makes it easy to correctly format multiple rows / columns of data. Just pass in the headers and rows to the method. The width and height will be dynamically calculated based on the given data: + + $headers = ['Name', 'Email']; + + $users = App\User::all(['name', 'email'])->toArray(); + + $this->table($headers, $users); + +#### Progress Bars + +For long running tasks, it could be helpful to show a progress indicator. Using the output object, we can start, advance and stop the Progress Bar. First, define the total number of steps the process will iterate through. Then, advance the Progress Bar after processing each item: + + $users = App\User::all(); + + $bar = $this->output->createProgressBar(count($users)); + + foreach ($users as $user) { + $this->performTask($user); + + $bar->advance(); + } + + $bar->finish(); + +For more advanced options, check out the [Symfony Progress Bar component documentation](https://symfony.com/doc/2.7/components/console/helpers/progressbar.html). + + +## Registering Commands + +Once your command is finished, you need to register it with Artisan. All commands are registered in the `app/Console/Kernel.php` file. Within this file, you will find a list of commands in the `commands` property. To register your command, simply add the command's class name to the list. When Artisan boots, all the commands listed in this property will be resolved by the [service container](/docs/{{version}}/container) and registered with Artisan: + + protected $commands = [ + Commands\SendEmails::class + ]; + + +## Programmatically Executing Commands + +Sometimes you may wish to execute an Artisan command outside of the CLI. For example, you may wish to fire an Artisan command from a route or controller. You may use the `call` method on the `Artisan` facade to accomplish this. The `call` method accepts the name of the command as the first argument, and an array of command parameters as the second argument. The exit code will be returned: + + Route::get('/foo', function () { + $exitCode = Artisan::call('email:send', [ + 'user' => 1, '--queue' => 'default' + ]); + + // + }); + +Using the `queue` method on the `Artisan` facade, you may even queue Artisan commands so they are processed in the background by your [queue workers](/docs/{{version}}/queues). Before using this method, make sure you have configured your queue and are running a queue listener: + + Route::get('/foo', function () { + Artisan::queue('email:send', [ + 'user' => 1, '--queue' => 'default' + ]); + + // + }); + +If you need to specify the value of an option that does not accept string values, such as the `--force` flag on the `migrate:refresh` command, you may pass `true` or `false`: + + $exitCode = Artisan::call('migrate:refresh', [ + '--force' => true, + ]); + + +### Calling Commands From Other Commands + +Sometimes you may wish to call other commands from an existing Artisan command. You may do so using the `call` method. This `call` method accepts the command name and an array of command parameters: + + /** + * Execute the console command. + * + * @return mixed + */ + public function handle() + { + $this->call('email:send', [ + 'user' => 1, '--queue' => 'default' + ]); + + // + } + +If you would like to call another console command and suppress all of its output, you may use the `callSilent` method. The `callSilent` method has the same signature as the `call` method: + + $this->callSilent('email:send', [ + 'user' => 1, '--queue' => 'default' + ]); diff --git a/authentication.md b/authentication.md new file mode 100644 index 0000000..99edacc --- /dev/null +++ b/authentication.md @@ -0,0 +1,535 @@ +# Authentication + +- [Introduction](#introduction) + - [Database Considerations](#introduction-database-considerations) +- [Authentication Quickstart](#authentication-quickstart) + - [Routing](#included-routing) + - [Views](#included-views) + - [Authenticating](#included-authenticating) + - [Retrieving The Authenticated User](#retrieving-the-authenticated-user) + - [Protecting Routes](#protecting-routes) + - [Login Throttling](#login-throttling) +- [Manually Authenticating Users](#authenticating-users) + - [Remembering Users](#remembering-users) + - [Other Authentication Methods](#other-authentication-methods) +- [HTTP Basic Authentication](#http-basic-authentication) + - [Stateless HTTP Basic Authentication](#stateless-http-basic-authentication) +- [Social Authentication](https://github.com/laravel/socialite) +- [Adding Custom Guards](#adding-custom-guards) +- [Adding Custom User Providers](#adding-custom-user-providers) + - [The User Provider Contract](#the-user-provider-contract) + - [The Authenticatable Contract](#the-authenticatable-contract) +- [Events](#events) + + +## Introduction + +> {tip} **Want to get started fast?** Just run `php artisan make:auth` and `php artisan migrate` in a fresh Laravel application. Then, navigate your browser to `http://your-app.dev/register` or any other URL that is assigned to your application. These two commands will take care of scaffolding your entire authentication system! + +Laravel makes implementing authentication very simple. In fact, almost everything is configured for you out of the box. The authentication configuration file is located at `config/auth.php`, which contains several well documented options for tweaking the behavior of the authentication services. + +At its core, Laravel's authentication facilities are made up of "guards" and "providers". Guards define how users are authenticated for each request. For example, Laravel ships with a `session` guard which maintains state using session storage and cookies. + +Providers define how users are retrieved from your persistent storage. Laravel ships with support for retrieving users using Eloquent and the database query builder. However, you are free to define additional providers as needed for your application. + +Don't worry if this all sounds confusing now! Many applications will never need to modify the default authentication configuration. + + +### Database Considerations + +By default, Laravel includes an `App\User` [Eloquent model](/docs/{{version}}/eloquent) in your `app` directory. This model may be used with the default Eloquent authentication driver. If your application is not using Eloquent, you may use the `database` authentication driver which uses the Laravel query builder. + +When building the database schema for the `App\User` model, make sure the password column is at least 60 characters in length. Maintaining the default string column length of 255 characters would be a good choice. + +Also, you should verify that your `users` (or equivalent) table contains a nullable, string `remember_token` column of 100 characters. This column will be used to store a token for users that select the "remember me" option when logging into your application. + + +## Authentication Quickstart + +Laravel ships with several pre-built authentication controllers, which are located in the `App\Http\Controllers\Auth` namespace. The `RegisterController` handles new user registration, the `LoginController` handles authentication, the `ForgotPasswordController` handles e-mailing links for resetting passwords, and the `ResetPasswordController` contains the logic to reset passwords. Each of these controllers uses a trait to include their necessary methods. For many applications, you will not need to modify these controllers at all. + + +### Routing + +Laravel provides a quick way to scaffold all of the routes and views you need for authentication using one simple command: + + php artisan make:auth + +This command should be used on fresh applications and will install a layout view, registration and login views, as well as routes for all authentication end-points. A `HomeController` will also be generated to handle post-login requests to your application's dashboard. + + +### Views + +As mentioned in the previous section, the `php artisan make:auth` command will create all of the views you need for authentication and place them in the `resources/views/auth` directory. + +The `make:auth` command will also create a `resources/views/layouts` directory containing a base layout for your application. All of these views use the Bootstrap CSS framework, but you are free to customize them however you wish. + + +### Authenticating + +Now that you have routes and views setup for the included authentication controllers, you are ready to register and authenticate new users for your application! You may simply access your application in a browser since the authentication controllers already contain the logic (via their traits) to authenticate existing users and store new users in the database. + +#### Path Customization + +When a user is successfully authenticated, they will be redirected to the `/home` URI. You can customize the post-authentication redirect location by defining a `redirectTo` property on the `LoginController`, `RegisterController`, and `ResetPasswordController`: + + protected $redirectTo = '/'; + +If the redirect path needs custom generation logic you may define a `redirectTo` method instead of a `redirectTo` property: + + protected function redirectTo() + { + // + } + +> {tip} The `redirectTo` method will take precedence over the `redirectTo` attribute. + +#### Username Customization + +By default, Laravel uses the `email` field for authentication. If you would like to customize this, you may define a `username` method on your `LoginController`: + + public function username() + { + return 'username'; + } + +#### Guard Customization + +You may also customize the "guard" that is used to authenticate and register users. To get started, define a `guard` method on your `LoginController`, `RegisterController`, and `ResetPasswordController`. The method should return a guard instance: + + use Illuminate\Support\Facades\Auth; + + protected function guard() + { + return Auth::guard('guard-name'); + } + +#### Validation / Storage Customization + +To modify the form fields that are required when a new user registers with your application, or to customize how new users are stored into your database, you may modify the `RegisterController` class. This class is responsible for validating and creating new users of your application. + +The `validator` method of the `RegisterController` contains the validation rules for new users of the application. You are free to modify this method as you wish. + +The `create` method of the `RegisterController` is responsible for creating new `App\User` records in your database using the [Eloquent ORM](/docs/{{version}}/eloquent). You are free to modify this method according to the needs of your database. + + +### Retrieving The Authenticated User + +You may access the authenticated user via the `Auth` facade: + + use Illuminate\Support\Facades\Auth; + + // Get the currently authenticated user... + $user = Auth::user(); + + // Get the currently authenticated user's ID... + $id = Auth::id(); + +Alternatively, once a user is authenticated, you may access the authenticated user via an `Illuminate\Http\Request` instance. Remember, type-hinted classes will automatically be injected into your controller methods: + + user() returns an instance of the authenticated user... + } + } + +#### Determining If The Current User Is Authenticated + +To determine if the user is already logged into your application, you may use the `check` method on the `Auth` facade, which will return `true` if the user is authenticated: + + use Illuminate\Support\Facades\Auth; + + if (Auth::check()) { + // The user is logged in... + } + +> {tip} Even though it is possible to determine if a user is authenticated using the `check` method, you will typically use a middleware to verify that the user is authenticated before allowing the user access to certain routes / controllers. To learn more about this, check out the documentation on [protecting routes](/docs/{{version}}/authentication#protecting-routes). + + +### Protecting Routes + +[Route middleware](/docs/{{version}}/middleware) can be used to only allow authenticated users to access a given route. Laravel ships with an `auth` middleware, which is defined at `Illuminate\Auth\Middleware\Authenticate`. Since this middleware is already registered in your HTTP kernel, all you need to do is attach the middleware to a route definition: + + Route::get('profile', function () { + // Only authenticated users may enter... + })->middleware('auth'); + +Of course, if you are using [controllers](/docs/{{version}}/controllers), you may call the `middleware` method from the controller's constructor instead of attaching it in the route definition directly: + + public function __construct() + { + $this->middleware('auth'); + } + +#### Specifying A Guard + +When attaching the `auth` middleware to a route, you may also specify which guard should be used to authenticate the user. The guard specified should correspond to one of the keys in the `guards` array of your `auth.php` configuration file: + + public function __construct() + { + $this->middleware('auth:api'); + } + + +### Login Throttling + +If you are using Laravel's built-in `LoginController` class, the `Illuminate\Foundation\Auth\ThrottlesLogins` trait will already be included in your controller. By default, the user will not be able to login for one minute if they fail to provide the correct credentials after several attempts. The throttling is unique to the user's username / e-mail address and their IP address. + + +## Manually Authenticating Users + +Of course, you are not required to use the authentication controllers included with Laravel. If you choose to remove these controllers, you will need to manage user authentication using the Laravel authentication classes directly. Don't worry, it's a cinch! + +We will access Laravel's authentication services via the `Auth` [facade](/docs/{{version}}/facades), so we'll need to make sure to import the `Auth` facade at the top of the class. Next, let's check out the `attempt` method: + + $email, 'password' => $password])) { + // Authentication passed... + return redirect()->intended('dashboard'); + } + } + } + +The `attempt` method accepts an array of key / value pairs as its first argument. The values in the array will be used to find the user in your database table. So, in the example above, the user will be retrieved by the value of the `email` column. If the user is found, the hashed password stored in the database will be compared with the hashed `password` value passed to the method via the array. If the two hashed passwords match an authenticated session will be started for the user. + +The `attempt` method will return `true` if authentication was successful. Otherwise, `false` will be returned. + +The `intended` method on the redirector will redirect the user to the URL they were attempting to access before being intercepted by the authentication middleware. A fallback URI may be given to this method in case the intended destination is not available. + +#### Specifying Additional Conditions + +If you wish, you also may add extra conditions to the authentication query in addition to the user's e-mail and password. For example, we may verify that user is marked as "active": + + if (Auth::attempt(['email' => $email, 'password' => $password, 'active' => 1])) { + // The user is active, not suspended, and exists. + } + +> {note} In these examples, `email` is not a required option, it is merely used as an example. You should use whatever column name corresponds to a "username" in your database. + +#### Accessing Specific Guard Instances + +You may specify which guard instance you would like to utilize using the `guard` method on the `Auth` facade. This allows you to manage authentication for separate parts of your application using entirely separate authenticatable models or user tables. + +The guard name passed to the `guard` method should correspond to one of the guards configured in your `auth.php` configuration file: + + if (Auth::guard('admin')->attempt($credentials)) { + // + } + +#### Logging Out + +To log users out of your application, you may use the `logout` method on the `Auth` facade. This will clear the authentication information in the user's session: + + Auth::logout(); + + +### Remembering Users + +If you would like to provide "remember me" functionality in your application, you may pass a boolean value as the second argument to the `attempt` method, which will keep the user authenticated indefinitely, or until they manually logout. Of course, your `users` table must include the string `remember_token` column, which will be used to store the "remember me" token. + + if (Auth::attempt(['email' => $email, 'password' => $password], $remember)) { + // The user is being remembered... + } + +> {tip} If you are using the built-in `LoginController` that is shipped with Laravel, the proper logic to "remember" users is already implemented by the traits used by the controller. + +If you are "remembering" users, you may use the `viaRemember` method to determine if the user was authenticated using the "remember me" cookie: + + if (Auth::viaRemember()) { + // + } + + +### Other Authentication Methods + +#### Authenticate A User Instance + +If you need to log an existing user instance into your application, you may call the `login` method with the user instance. The given object must be an implementation of the `Illuminate\Contracts\Auth\Authenticatable` [contract](/docs/{{version}}/contracts). Of course, the `App\User` model included with Laravel already implements this interface: + + Auth::login($user); + + // Login and "remember" the given user... + Auth::login($user, true); + +Of course, you may specify the guard instance you would like to use: + + Auth::guard('admin')->login($user); + +#### Authenticate A User By ID + +To log a user into the application by their ID, you may use the `loginUsingId` method. This method simply accepts the primary key of the user you wish to authenticate: + + Auth::loginUsingId(1); + + // Login and "remember" the given user... + Auth::loginUsingId(1, true); + +#### Authenticate A User Once + +You may use the `once` method to log a user into the application for a single request. No sessions or cookies will be utilized, which means this method may be helpful when building a stateless API: + + if (Auth::once($credentials)) { + // + } + + +## HTTP Basic Authentication + +[HTTP Basic Authentication](https://en.wikipedia.org/wiki/Basic_access_authentication) provides a quick way to authenticate users of your application without setting up a dedicated "login" page. To get started, attach the `auth.basic` [middleware](/docs/{{version}}/middleware) to your route. The `auth.basic` middleware is included with the Laravel framework, so you do not need to define it: + + Route::get('profile', function () { + // Only authenticated users may enter... + })->middleware('auth.basic'); + +Once the middleware has been attached to the route, you will automatically be prompted for credentials when accessing the route in your browser. By default, the `auth.basic` middleware will use the `email` column on the user record as the "username". + +#### A Note On FastCGI + +If you are using PHP FastCGI, HTTP Basic authentication may not work correctly out of the box. The following lines should be added to your `.htaccess` file: + + RewriteCond %{HTTP:Authorization} ^(.+)$ + RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] + + +### Stateless HTTP Basic Authentication + +You may also use HTTP Basic Authentication without setting a user identifier cookie in the session, which is particularly useful for API authentication. To do so, [define a middleware](/docs/{{version}}/middleware) that calls the `onceBasic` method. If no response is returned by the `onceBasic` method, the request may be passed further into the application: + + middleware('auth.basic.once'); + + +## Adding Custom Guards + +You may define your own authentication guards using the `extend` method on the `Auth` facade. You should place this call to `provider` within a [service provider](/docs/{{version}}/providers). Since Laravel already ships with an `AuthServiceProvider`, we can place the code in that provider: + + registerPolicies(); + + Auth::extend('jwt', function ($app, $name, array $config) { + // Return an instance of Illuminate\Contracts\Auth\Guard... + + return new JwtGuard(Auth::createUserProvider($config['provider'])); + }); + } + } + +As you can see in the example above, the callback passed to the `extend` method should return an implementation of `Illuminate\Contracts\Auth\Guard`. This interface contains a few methods you will need to implement to define a custom guard. Once your custom guard has been defined, you may use the guard in the `guards` configuration of your `auth.php` configuration file: + + 'guards' => [ + 'api' => [ + 'driver' => 'jwt', + 'provider' => 'users', + ], + ], + + +## Adding Custom User Providers + +If you are not using a traditional relational database to store your users, you will need to extend Laravel with your own authentication user provider. We will use the `provider` method on the `Auth` facade to define a custom user provider: + + registerPolicies(); + + Auth::provider('riak', function ($app, array $config) { + // Return an instance of Illuminate\Contracts\Auth\UserProvider... + + return new RiakUserProvider($app->make('riak.connection')); + }); + } + } + +After you have registered the provider using the `provider` method, you may switch to the new user provider in your `auth.php` configuration file. First, define a `provider` that uses your new driver: + + 'providers' => [ + 'users' => [ + 'driver' => 'riak', + ], + ], + +Finally, you may use this provider in your `guards` configuration: + + 'guards' => [ + 'web' => [ + 'driver' => 'session', + 'provider' => 'users', + ], + ], + + +### The User Provider Contract + +The `Illuminate\Contracts\Auth\UserProvider` implementations are only responsible for fetching a `Illuminate\Contracts\Auth\Authenticatable` implementation out of a persistent storage system, such as MySQL, Riak, etc. These two interfaces allow the Laravel authentication mechanisms to continue functioning regardless of how the user data is stored or what type of class is used to represent it. + +Let's take a look at the `Illuminate\Contracts\Auth\UserProvider` contract: + + getAuthPassword()` to the value of `$credentials['password']`. This method should return `true` or `false` indicating on whether the password is valid. + + +### The Authenticatable Contract + +Now that we have explored each of the methods on the `UserProvider`, let's take a look at the `Authenticatable` contract. Remember, the provider should return implementations of this interface from the `retrieveById` and `retrieveByCredentials` methods: + + +## Events + +Laravel raises a variety of [events](/docs/{{version}}/events) during the authentication process. You may attach listeners to these events in your `EventServiceProvider`: + + /** + * The event listener mappings for the application. + * + * @var array + */ + protected $listen = [ + 'Illuminate\Auth\Events\Registered' => [ + 'App\Listeners\LogRegisteredUser', + ], + + 'Illuminate\Auth\Events\Attempting' => [ + 'App\Listeners\LogAuthenticationAttempt', + ], + + 'Illuminate\Auth\Events\Authenticated' => [ + 'App\Listeners\LogAuthenticated', + ], + + 'Illuminate\Auth\Events\Login' => [ + 'App\Listeners\LogSuccessfulLogin', + ], + + 'Illuminate\Auth\Events\Failed' => [ + 'App\Listeners\LogFailedLogin', + ], + + 'Illuminate\Auth\Events\Logout' => [ + 'App\Listeners\LogSuccessfulLogout', + ], + + 'Illuminate\Auth\Events\Lockout' => [ + 'App\Listeners\LogLockout', + ], + ]; diff --git a/authorization.md b/authorization.md new file mode 100644 index 0000000..8974037 --- /dev/null +++ b/authorization.md @@ -0,0 +1,327 @@ +# Authorization + +- [Introduction](#introduction) +- [Gates](#gates) + - [Writing Gates](#writing-gates) + - [Authorizing Actions](#authorizing-actions-via-gates) +- [Creating Policies](#creating-policies) + - [Generating Policies](#generating-policies) + - [Registering Policies](#registering-policies) +- [Writing Policies](#writing-policies) + - [Policy Methods](#policy-methods) + - [Methods Without Models](#methods-without-models) + - [Policy Filters](#policy-filters) +- [Authorizing Actions Using Policies](#authorizing-actions-using-policies) + - [Via The User Model](#via-the-user-model) + - [Via Middleware](#via-middleware) + - [Via Controller Helpers](#via-controller-helpers) + - [Via Blade Templates](#via-blade-templates) + + +## Introduction + +In addition to providing [authentication](/docs/{{version}}/authentication) services out of the box, Laravel also provides a simple way to authorize user actions against a given resource. Like authentication, Laravel's approach to authorization is simple, and there are two primary ways of authorizing actions: gates and policies. + +Think of gates and policies like routes and controllers. Gates provide a simple, Closure based approach to authorization while policies, like controllers, group their logic around a particular model or resource. We'll explore gates first and then examine policies. + +You do not need to choose between exclusively using gates or exclusively using policies when building an application. Most applications will most likely contain a mixture of gates and policies, and that is perfectly fine! Gates are most applicable to actions which are not related to any model or resource, such as viewing an administrator dashboard. In contrast, policies should be used when you wish to authorize an action for a particular model or resource. + + +## Gates + + +### Writing Gates + +Gates are Closures that determine if a user is authorized to perform a given action and are typically defined in the `App\Providers\AuthServiceProvider` class using the `Gate` facade. Gates always receive a user instance as their first argument, and may optionally receive additional arguments such as a relevant Eloquent model: + + /** + * Register any authentication / authorization services. + * + * @return void + */ + public function boot() + { + $this->registerPolicies(); + + Gate::define('update-post', function ($user, $post) { + return $user->id == $post->user_id; + }); + } + + +### Authorizing Actions + +To authorize an action using gates, you should use the `allows` or `denies` methods. Note that you are not required to pass the currently authenticated user to these methods. Laravel will automatically take care of passing the user into the gate Closure: + + if (Gate::allows('update-post', $post)) { + // The current user can update the post... + } + + if (Gate::denies('update-post', $post)) { + // The current user can't update the post... + } + +If you would like to determine if a particular user is authorized to perform an action, you may use the `forUser` method on the `Gate` facade: + + if (Gate::forUser($user)->allows('update-post', $post)) { + // The user can update the post... + } + + if (Gate::forUser($user)->denies('update-post', $post)) { + // The user can't update the post... + } + + +## Creating Policies + + +### Generating Policies + +Policies are classes that organize authorization logic around a particular model or resource. For example, if your application is a blog, you may have a `Post` model and a corresponding `PostPolicy` to authorize user actions such as creating or updating posts. + +You may generate a policy using the `make:policy` [artisan command](/docs/{{version}}/artisan). The generated policy will be placed in the `app/Policies` directory. If this directory does not exist in your application, Laravel will create it for you: + + php artisan make:policy PostPolicy + +The `make:policy` command will generate an empty policy class. If you would like to generate a class with the basic "CRUD" policy methods already included in the class, you may specify a `--model` when executing the command: + + php artisan make:policy PostPolicy --model=Post + +> {tip} All policies are resolved via the Laravel [service container](/docs/{{version}}/container), allowing you to type-hint any needed dependencies in the policy's constructor to have them automatically injected. + + +### Registering Policies + +Once the policy exists, it needs to be registered. The `AuthServiceProvider` included with fresh Laravel applications contains a `policies` property which maps your Eloquent models to their corresponding policies. Registering a policy will instruct Laravel which policy to utilize when authorizing actions against a given model: + + PostPolicy::class, + ]; + + /** + * Register any application authentication / authorization services. + * + * @return void + */ + public function boot() + { + $this->registerPolicies(); + + // + } + } + + +## Writing Policies + + +### Policy Methods + +Once the policy has been registered, you may add methods for each action it authorizes. For example, let's define an `update` method on our `PostPolicy` which determines if a given `User` can update a given `Post` instance. + +The `update` method will receive a `User` and a `Post` instance as its arguments, and should return `true` or `false` indicating whether the user is authorized to update the given `Post`. So, for this example, let's verify that the user's `id` matches the `user_id` on the post: + + id === $post->user_id; + } + } + +You may continue to define additional methods on the policy as needed for the various actions it authorizes. For example, you might define `view` or `delete` methods to authorize various `Post` actions, but remember you are free to give your policy methods any name you like. + +> {tip} If you used the `--model` option when generating your policy via the Artisan console, it will already contain methods for the `view`, `create`, `update`, and `delete` actions. + + +### Methods Without Models + +Some policy methods only receive the currently authenticated user and not an instance of the model they authorize. This situation is most common when authorizing `create` actions. For example, if you are creating a blog, you may wish to check if a user is authorized to create any posts at all. + +When defining policy methods that will not receive a model instance, such as a `create` method, it will not receive a model instance. Instead, you should define the method as only expecting the authenticated user: + + /** + * Determine if the given user can create posts. + * + * @param \App\User $user + * @return bool + */ + public function create(User $user) + { + // + } + + +### Policy Filters + +For certain users, you may wish to authorize all actions within a given policy. To accomplish this, define a `before` method on the policy. The `before` method will be executed before any other methods on the policy, giving you an opportunity to authorize the action before the intended policy method is actually called. This feature is most commonly used for authorizing application administrators to perform any action: + + public function before($user, $ability) + { + if ($user->isSuperAdmin()) { + return true; + } + } + +If you would like to deny all authorizations for a user you should return `false` from the `before` method. If `null` is returned, the authorization will fall through to the policy method. + + +## Authorizing Actions Using Policies + + +### Via The User Model + +The `User` model that is included with your Laravel application includes two helpful methods for authorizing actions: `can` and `cant`. The `can` method receives the action you wish to authorize and the relevant model. For example, let's determine if a user is authorized to update a given `Post` model: + + if ($user->can('update', $post)) { + // + } + +If a [policy is registered](#registering-policies) for the given model, the `can` method will automatically call the appropriate policy and return the boolean result. If no policy is registered for the model, the `can` method will attempt to call the Closure based Gate matching the given action name. + +#### Actions That Don't Require Models + +Remember, some actions like `create` may not require a model instance. In these situations, you may pass a class name to the `can` method. The class name will be used to determine which policy to use when authorizing the action: + + use App\Post; + + if ($user->can('create', Post::class)) { + // Executes the "create" method on the relevant policy... + } + + +### Via Middleware + +Laravel includes a middleware that can authorize actions before the incoming request even reaches your routes or controllers. By default, the `Illuminate\Auth\Middleware\Authorize` middleware is assigned the `can` key in your `App\Http\Kernel` class. Let's explore an example of using the `can` middleware to authorize that a user can update a blog post: + + use App\Post; + + Route::put('/post/{post}', function (Post $post) { + // The current user may update the post... + })->middleware('can:update,post'); + +In this example, we're passing the `can` middleware two arguments. The first is the name of the action we wish to authorize and the second is the route parameter we wish to pass to the policy method. In this case, since we are using [implicit model binding](/docs/{{version}}/routing#implicit-binding), a `Post` model will be passed to the policy method. If the user is not authorized to perform the given action, a HTTP response with a `403` status code will be generated by the middleware. + +#### Actions That Don't Require Models + +Again, some actions like `create` may not require a model instance. In these situations, you may pass a class name to the middleware. The class name will be used to determine which policy to use when authorizing the action: + + Route::post('/post', function () { + // The current user may create posts... + })->middleware('can:create,App\Post'); + + +### Via Controller Helpers + +In addition to helpful methods provided to the `User` model, Laravel provides a helpful `authorize` method to any of your controllers which extend the `App\Http\Controllers\Controller` base class. Like the `can` method, this method accepts the name of the action you wish to authorize and the relevant model. If the action is not authorized, the `authorize` method will throw an `Illuminate\Auth\Access\AuthorizationException`, which the default Laravel exception handler will convert to an HTTP response with a `403` status code: + + authorize('update', $post); + + // The current user can update the blog post... + } + } + +#### Actions That Don't Require Models + +As previously discussed, some actions like `create` may not require a model instance. In these situations, you may pass a class name to the `authorize` method. The class name will be used to determine which policy to use when authorizing the action: + + /** + * Create a new blog post. + * + * @param Request $request + * @return Response + */ + public function create(Request $request) + { + $this->authorize('create', Post::class); + + // The current user can create blog posts... + } + + +### Via Blade Templates + +When writing Blade templates, you may wish to display a portion of the page only if the user is authorized to perform a given action. For example, you may wish to show an update form for a blog post only if the user can actually update the post. In this situation, you may use the `@can` and `@cannot` family of directives: + + @can('update', $post) + + @elsecan('create', $post) + + @endcan + + @cannot('update', $post) + + @elsecannot('create', $post) + + @endcannot + +These directives are convenient shortcuts for writing `@if` and `@unless` statements. The `@can` and `@cannot` statements above respectively translate to the following statements: + + @if (Auth::user()->can('update', $post)) + + @endif + + @unless (Auth::user()->can('update', $post)) + + @endunless + +#### Actions That Don't Require Models + +Like most of the other authorization methods, you may pass a class name to the `@can` and `@cannot` directives if the action does not require a model instance: + + @can('create', Post::class) + + @endcan + + @cannot('create', Post::class) + + @endcannot diff --git a/billing.md b/billing.md index 05cf532..83f7e5d 100644 --- a/billing.md +++ b/billing.md @@ -2,230 +2,624 @@ - [Introduction](#introduction) - [Configuration](#configuration) -- [Subscribing To A Plan](#subscribing-to-a-plan) -- [No Card Up Front](#no-card-up-front) -- [Swapping Subscriptions](#swapping-subscriptions) -- [Subscription Quantity](#subscription-quantity) -- [Cancelling A Subscription](#cancelling-a-subscription) -- [Resuming A Subscription](#resuming-a-subscription) -- [Checking Subscription Status](#checking-subscription-status) -- [Handling Failed Payments](#handling-failed-payments) + - [Stripe](#stripe-configuration) + - [Braintree](#braintree-configuration) + - [Currency Configuration](#currency-configuration) +- [Subscriptions](#subscriptions) + - [Creating Subscriptions](#creating-subscriptions) + - [Checking Subscription Status](#checking-subscription-status) + - [Changing Plans](#changing-plans) + - [Subscription Quantity](#subscription-quantity) + - [Subscription Taxes](#subscription-taxes) + - [Cancelling Subscriptions](#cancelling-subscriptions) + - [Resuming Subscriptions](#resuming-subscriptions) + - [Updating Credit Cards](#updating-credit-cards) +- [Subscription Trials](#subscription-trials) + - [With Credit Card Up Front](#with-credit-card-up-front) + - [Without Credit Card Up Front](#without-credit-card-up-front) +- [Handling Stripe Webhooks](#handling-stripe-webhooks) + - [Defining Webhook Event Handlers](#defining-webhook-event-handlers) + - [Failed Subscriptions](#handling-failed-subscriptions) +- [Handling Braintree Webhooks](#handling-braintree-webhooks) + - [Defining Webhook Event Handlers](#defining-braintree-webhook-event-handlers) + - [Failed Subscriptions](#handling-braintree-failed-subscriptions) +- [Single Charges](#single-charges) - [Invoices](#invoices) + - [Generating Invoice PDFs](#generating-invoice-pdfs) ## Introduction -Laravel Cashier က Subscription Billing Service တစ်ခုဖြစ်တဲ့ Stripe သုံးတဲ့အခါ ပိုပြီးလွယ်ကူစေအောင်လို့ လုပ်ပေးထားပါတယ်။ Stripe သုံးဖို့အတွက် အစအဆုံး ပြန်ရေးနေစရာမလိုတော့အောင်လို့ အခြေခံ Code တွေ ရေးထားပြီးသားဖြစ်ပါတယ်။ အခြေခံ Subscription Management အပြင် , Coupons, Subscription ကို Upgrade လုပ်တဲ့ Feature (Swap), Subscription Quantities, Subscription ကို သတ်မှတ်ထားတဲ့ ကာလအတွင်း Subscription ကို Cancel လုပ်လို့ရမယ့် Feature လည်းပါဝင်ပါတယ်။ နောက် Invoice ကို PDF ထုတ်လို့ရအောင်လဲ ကူညီပေးပါတယ်။ +Laravel Cashier provides an expressive, fluent interface to [Stripe's](https://stripe.com) and [Braintree's](https://www.braintreepayments.com) subscription billing services. It handles almost all of the boilerplate subscription billing code you are dreading writing. In addition to basic subscription management, Cashier can handle coupons, swapping subscription, subscription "quantities", cancellation grace periods, and even generate invoice PDFs. + +> {note} If you're only performing "one-off" charges and do not offer subscriptions. You should not use Cashier. You should use the Stripe and Braintree SDKs directly. ## Configuration + +### Stripe + #### Composer -ပထမဆုံး သင့်ရဲ့ Composer File မှာ Casher package ကိုထည့်ပေးပါ၊ +First, add the Cashier package for Stripe to your `composer.json` file and run the `composer update` command: - "laravel/cashier": "~2.0" + "laravel/cashier": "~7.0" #### Service Provider -နောက်... သင်ရဲ့ `app` configuration file ထဲမှာ `Laravel\Cashier\CashierServiceProvider` ကို regiter လုပ်ပါ၊ +Next, register the `Laravel\Cashier\CashierServiceProvider` [service provider](/docs/{{version}}/providers) in your `config/app.php` configuration file. + +#### Database Migrations + +Before using Cashier, we'll also need to [prepare the database](/docs/{{version}}/migrations). We need to add several columns to your `users` table and create a new `subscriptions` table to hold all of our customer's subscriptions: -#### Migration + Schema::table('users', function ($table) { + $table->string('stripe_id')->nullable(); + $table->string('card_brand')->nullable(); + $table->string('card_last_four')->nullable(); + $table->timestamp('trial_ends_at')->nullable(); + }); -Chashier ကိုမသုံးခင်မှာ... columns တစ်ချို့ကို သင့်ရဲ့ database ထဲကို add လုပ်ဖို့လိုပါမယ်။ မစိုးရိမ်ပါနဲ့... လိုအပ်တဲ့ column တွေကိုထက်ထည့်ဖို့ `cashier:table` Artisan command ကိုသုံးနိုင်ပါတယ်။ + Schema::create('subscriptions', function ($table) { + $table->increments('id'); + $table->integer('user_id'); + $table->string('name'); + $table->string('stripe_id'); + $table->string('stripe_plan'); + $table->integer('quantity'); + $table->timestamp('trial_ends_at')->nullable(); + $table->timestamp('ends_at')->nullable(); + $table->timestamps(); + }); -#### Model Setup +Once the migrations have been created, run the `migrate` Artisan command. -နောက်... သင့်ရဲ့ model definition မှာ BillableTrait နဲ့ appropriate date mutators တွေကို add လိုက်ပါ: +#### Billable Model - use Laravel\Cashier\BillableTrait; - use Laravel\Cashier\BillableInterface; +Next, add the `Billable` trait to your model definition. This trait provides various methods to allow you to perform common billing tasks, such as creating subscriptions, applying coupons, and updating credit card information: - class User extends Eloquent implements BillableInterface { + use Laravel\Cashier\Billable; - use BillableTrait; + class User extends Authenticatable + { + use Billable; + } - protected $dates = ['trial_ends_at', 'subscription_ends_at']; +#### API Keys - } +Finally, you should configure your Stripe key in your `services.php` configuration file. You can retrieve your Stripe API keys from the Stripe control panel: -#### Stripe Key + 'stripe' => [ + 'model' => App\User::class, + 'secret' => env('STRIPE_SECRET'), + ], -နောက်ဆုံးမှာတော့ သင့်ရဲ့ Stripe key ကိုသင့်ရဲ့ bootstrap files တစ်ခုထဲမှာ set လုပ်လိုက်ပါ + +### Braintree - User::setStripeKey('stripe-key'); +#### Braintree Caveats - -## Subscribing To A Plan +For many operations, the Stripe and Braintree implementations of Cashier function the same. Both services provide subscription billing with credit cards but Braintree also supports payments via PayPal. However, Braintree also lacks some features that are supported by Stripe. You should keep the following in mind when deciding to use Stripe or Braintree: -user ကို Stripe plan တစ်ခုပေးဖို့ သင့်မှာ model instance တစ်ခုရှိတယ်ဆိုရင် လွယ်လွယ်ကူကူ subscribe လုပ်နိုင်ပါတယ် - $user = User::find(1); +
    +- Braintree supports PayPal while Stripe does not. +- Braintree does not support the `increment` and `decrement` methods on subscriptions. This is a Braintree limitation, not a Cashier limitation. +- Braintree does not support percentage based discounts. This is a Braintree limitation, not a Cashier limitation. +
    - $user->subscription('monthly')->create($creditCardToken); +#### Composer + +First, add the Cashier package for Braintree to your `composer.json` file and run the `composer update` command: -subscription ကို create လုပ်ပြီးသွားပြီဆိုရင် သင့်အနေနဲ့ cupon ကို apply လုပ်ဖို့ `withCoupon` ကိုသုံးနိုင်ပါတယ် + "laravel/cashier-braintree": "~2.0" - $user->subscription('monthly') - ->withCoupon('code') - ->create($creditCardToken); +#### Service Provider -Stripe subscription ကို `subscription` method က automatically create လုပ်သွားလိမ့်မယ်... သင့်ရဲ့ Strip customer ID နဲ့ အခြား billing information နဲ့ပတ်သတ်တဲ့ database တွေကော update လုပ်သွားပါလိမ့်မယ်။ +Next, register the `Laravel\Cashier\CashierServiceProvider` [service provider](/docs/{{version}}/providers) in your `config/app.php` configuration file. -သင့်မှာ trail period ရှိတယ်ဆိုရင် သင့်ရဲ့ model မှာ trial end date ကို subscribing လုပ်ပြီးမှာ set လုပ်ထားရဲ့လားဆိုတာကိုသေချာ make sure လုပ်ပါ။ +#### Plan Credit Coupon - $user->trial_ends_at = Carbon::now()->addDays(14); +Before using Cashier with Braintree, you will need to define a `plan-credit` discount in your Braintree control panel. This discount will be used to properly prorate subscriptions that change from yearly to monthly billing, or from monthly to yearly billing. - $user->save(); +The discount amount configured in the Braintree control panel can be any value you wish, as Cashier will simply override the defined amount with our own custom amount each time we apply the coupon. This coupon is needed since Braintree does not natively support prorating subscriptions across subscription frequencies. - -## No Card Up Front -သင့်ရဲ့ application က ပထမဆုံး free-trial တစ်ခုကို credit-card မပါဘဲ လက်ခံမယ်ဆိုရင် `cardUpFront` ကိုသင့်ရဲ့ modle မှာ `false` ဆိုပြီး set လုပ်ပါ... +#### Database Migrations - protected $cardUpFront = false; +Before using Cashier, we'll need to [prepare the database](/docs/{{version}}/migrations). We need to add several columns to your `users` table and create a new `subscriptions` table to hold all of our customer's subscriptions: -Account creation မှာ trial နောက်ဆုံးရက်ကို model မှာ set လုပ်ထားရဲ့လားဆိုတာကို make sure လုပ်ပါ... + Schema::table('users', function ($table) { + $table->string('braintree_id')->nullable(); + $table->string('paypal_email')->nullable(); + $table->string('card_brand')->nullable(); + $table->string('card_last_four')->nullable(); + $table->timestamp('trial_ends_at')->nullable(); + }); - $user->trial_ends_at = Carbon::now()->addDays(14); + Schema::create('subscriptions', function ($table) { + $table->increments('id'); + $table->integer('user_id'); + $table->string('name'); + $table->string('braintree_id'); + $table->string('braintree_plan'); + $table->integer('quantity'); + $table->timestamp('trial_ends_at')->nullable(); + $table->timestamp('ends_at')->nullable(); + $table->timestamps(); + }); - $user->save(); +Once the migrations have been created, simply run the `migrate` Artisan command. - -## Swapping Subscriptions +#### Billable Model -Subscription အသစ်တစ်ခုမှာ user တစ်ယောက် ကို swap လုပ်ချင်တယ်ဆိုရင် `swap` method ကိုသုံးပါ... +Next, add the `Billable` trait to your model definition: - $user->subscription('premium')->swap(); + use Laravel\Cashier\Billable; -တကယ်လို့ user က trial မှာဘဲရှိနေတယ် ဆိုရင် trial က ပုံမှန် maintained လုပ်သွားပါ့မယ်။ နောက် subscription အတွက် "quantity" တစ်ခုရှိတယ်ဆိုရင် အဲ့ဒီ့ quantity ကိုလည်း maintain လုပ်သွားပါ့မယ်။ + class User extends Authenticatable + { + use Billable; + } - -## Subscription Quantity +#### API Keys + +Next, You should configure the following options in your `services.php` file: + + 'braintree' => [ + 'model' => App\User::class, + 'environment' => env('BRAINTREE_ENV'), + 'merchant_id' => env('BRAINTREE_MERCHANT_ID'), + 'public_key' => env('BRAINTREE_PUBLIC_KEY'), + 'private_key' => env('BRAINTREE_PRIVATE_KEY'), + ], + +Then you should add the following Braintree SDK calls to your `AppServiceProvider` service provider's `boot` method: + + \Braintree_Configuration::environment(config('services.braintree.environment')); + \Braintree_Configuration::merchantId(config('services.braintree.merchant_id')); + \Braintree_Configuration::publicKey(config('services.braintree.public_key')); + \Braintree_Configuration::privateKey(config('services.braintree.private_key')); + + +### Currency Configuration + +The default Cashier currency is United States Dollars (USD). You can change the default currency by calling the `Cashier::useCurrency` method from within the `boot` method of one of your service providers. The `useCurrency` method accepts two string parameters: the currency and the currency's symbol: + + use Laravel\Cashier\Cashier; + + Cashier::useCurrency('eur', '€'); -တစ်ခါတစ်လေမှာ subscriptions တွေက "quantity" ကနေပြီးတော့ affect ဖြစ်တယ်။ ဥပမာ... သင့်ရဲ့ application က user account တစ်ခုအတွက် တစ်လ ကို $10 charge လုပ်တယ်ဆိုပါတော့။ သင့်ရဲ့ subscription quantity ကို တိုးချင်တာဘဲဖြစ်ဖြစ်၊ လျော့ချင်တာဘဲဖြစ်ဖြစ် လွယ်လွယ်ကူကူ လုပ်ချင်တယ်ဆိုရင် `increment` နဲ့ `decrement` methods ကိုသုံးနိုင်ပါတယ် + +## Subscriptions - $user = User::find(1); + +### Creating Subscriptions - $user->subscription()->increment(); +To create a subscription, first retrieve an instance of your billable model, which typically will be an instance of `App\User`. Once you have retrieved the model instance, you may use the `newSubscription` method to create the model's subscription: - // Add five to the subscription's current quantity... - $user->subscription()->increment(5) + $user = User::find(1); - $user->subscription->decrement(); + $user->newSubscription('main', 'monthly')->create($stripeToken); - // Subtract five to the subscription's current quantity... - $user->subscription()->decrement(5) +The first argument passed to the `newSubscription` method should be the name of the subscription. If your application only offers a single subscription, you might call this `main` or `primary`. The second argument is the specific Stripe / Braintree plan the user is subscribing to. This value should correspond to the plan's identifier in Stripe or Braintree. - -## Cancelling A Subscription +The `create` method will begin the subscription as well as update your database with the customer ID and other relevant billing information. -Subscription တစ်ခုကို Cancel လုပ်တာ ပန်ခြံထဲမှာ လမ်းလျှောက်ရသလိုပါဘဲ... +#### Additional User Details - $user->subscription()->cancel(); +If you would like to specify additional customer details, you may do so by passing them as the second argument to the `create` method: -Subscription တစ်ခု cancel လုပ်သွားတဲ့အချိန်မှာ Casher က `subscription_ends_at` column ကို သင့်ရဲ့ database မှာ အလိုလို set လုပ်သွားပါ့မယ်။ ဥပမာ၊ customer က March လတစ်ရက်နေ့မှာ subscription ကို Cancel လုပ်သွားတယ် နောက် March 5 ရက်နေ့မှာ subscription end ဖြစ်မယ်လို့ schedule လည်းမရှိဘူးဆိုရင် `subscribed` method က March လ 5 ရက်နေ့အထိ return `true` ပြန်နေမှာပါ။ + $user->newSubscription('main', 'monthly')->create($stripeToken, [ + 'email' => $email, + ]); - -## Resuming A Subscription +To learn more about the additional fields supported by Stripe or Braintree, check out Stripe's [documentation on customer creation](https://stripe.com/docs/api#create_customer) or the corresponding [Braintree documentation](https://developers.braintreepayments.com/reference/request/customer/create/php). -User တစ်ယောက်ကသူရဲ့ subscription ကို cancelled လုပ်သွားတဲ့အချိန်မှာ သင့်အနေနဲ့ သူတို့ resume ပြန်လုပ်ဖို့ဆုတောင်းနေမှာပေါ့၊ ဒါဆိုရင် `resume` method ကိုသုံးလိုက်ပါ: +#### Coupons - $user->subscription('monthly')->resume($creditCardToken); +If you would like to apply a coupon when creating the subscription, you may use the `withCoupon` method: -တကယ်လို့ user က subscription တစ်ခုကို cancels လုပ်လိုက်တယ်၊ နောက် subscription က fully expired မဖြစ်ခင်မှာ user က resume ပြန်လုပ်လိုက်တယ်ဆိုရင် သူတို့က bill တွေကိုချက်ချင်းမဖြတ်ပါဘူး။ သူတို့ရဲ့ subscription တွေကို ရိုးရှင်းစွာပဲ re-activated လုပ်သွားပါတယ် နောက် သူတို့ရဲ့ မူလ billing cycle အတိုင်း billed လုပ်ပါလိမ့်မယ်။ + $user->newSubscription('main', 'monthly') + ->withCoupon('code') + ->create($stripeToken); -## Checking Subscription Status +### Checking Subscription Status + +Once a user is subscribed to your application, you may easily check their subscription status using a variety of convenient methods. First, the `subscribed` method returns `true` if the user has an active subscription, even if the subscription is currently within its trial period: + + if ($user->subscribed('main')) { + // + } + +The `subscribed` method also makes a great candidate for a [route middleware](/docs/{{version}}/middleware), allowing you to filter access to routes and controllers based on the user's subscription status: + + public function handle($request, Closure $next) + { + if ($request->user() && ! $request->user()->subscribed('main')) { + // This user is not a paying customer... + return redirect('billing'); + } + + return $next($request); + } + +If you would like to determine if a user is still within their trial period, you may use the `onTrial` method. This method can be useful for displaying a warning to the user that they are still on their trial period: + + if ($user->subscription('main')->onTrial()) { + // + } + +The `subscribedToPlan` method may be used to determine if the user is subscribed to a given plan based on a given Stripe / Braintree plan ID. In this example, we will determine if the user's `main` subscription is actively subscribed to the `monthly` plan: + + if ($user->subscribedToPlan('monthly', 'main')) { + // + } + +#### Cancelled Subscription Status + +To determine if the user was once an active subscriber, but has cancelled their subscription, you may use the `cancelled` method: + + if ($user->subscription('main')->cancelled()) { + // + } + +You may also determine if a user has cancelled their subscription, but are still on their "grace period" until the subscription fully expires. For example, if a user cancels a subscription on March 5th that was originally scheduled to expire on March 10th, the user is on their "grace period" until March 10th. Note that the `subscribed` method still returns `true` during this time: + + if ($user->subscription('main')->onGracePeriod()) { + // + } + + +### Changing Plans + +After a user is subscribed to your application, they may occasionally want to change to a new subscription plan. To swap a user to a new subscription, pass the plan's identifier to the `swap` method: + + $user = App\User::find(1); + + $user->subscription('main')->swap('provider-plan-id'); + +If the user is on trial, the trial period will be maintained. Also, if a "quantity" exists for the subscription, that quantity will also be maintained. + +If you would like to swap plans and cancel any trial period the user is currently on, you may use the `skipTrial` method: + + $user->subscription('main') + ->skipTrial() + ->swap('provider-plan-id'); + + +### Subscription Quantity + +> {note} Subscription quantities are only supported by the Stripe edition of Cashier. Braintree does not have a feature that corresponds to Stripe's "quantity". + +Sometimes subscriptions are affected by "quantity". For example, your application might charge $10 per month **per user** on an account. To easily increment or decrement your subscription quantity, use the `incrementQuantity` and `decrementQuantity` methods: + + $user = User::find(1); + + $user->subscription('main')->incrementQuantity(); + + // Add five to the subscription's current quantity... + $user->subscription('main')->incrementQuantity(5); + + $user->subscription('main')->decrementQuantity(); + + // Subtract five to the subscription's current quantity... + $user->subscription('main')->decrementQuantity(5); + +Alternatively, you may set a specific quantity using the `updateQuantity` method: + + $user->subscription('main')->updateQuantity(10); + +For more information on subscription quantities, consult the [Stripe documentation](https://stripe.com/docs/guides/subscriptions#setting-quantities). + + +### Subscription Taxes + +To specify the tax percentage a user pays on a subscription, implement the `taxPercentage` method on your billable model, and return a numeric value between 0 and 100, with no more than 2 decimal places. + + public function taxPercentage() { + return 20; + } + +The `taxPercentage` method enables you to apply a tax rate on a model-by-model basis, which may be helpful for a user base that spans multiple countries and tax rates. + +> {note} The `taxPercentage` method only applies to subscription charges. If you use Cashier to make "one off" charges, you will need to manually specify the tax rate at that time. + + +### Cancelling Subscriptions + +To cancel a subscription, simply call the `cancel` method on the user's subscription: + + $user->subscription('main')->cancel(); + +When a subscription is cancelled, Cashier will automatically set the `ends_at` column in your database. This column is used to know when the `subscribed` method should begin returning `false`. For example, if a customer cancels a subscription on March 1st, but the subscription was not scheduled to end until March 5th, the `subscribed` method will continue to return `true` until March 5th. + +You may determine if a user has cancelled their subscription but are still on their "grace period" using the `onGracePeriod` method: + + if ($user->subscription('main')->onGracePeriod()) { + // + } + +If you wish to cancel a subscription immediately, call the `cancelNow` method on the user's subscription: -User တစ်ယောက်က သင့်ရဲ့ application ကို subscribed လုပ်သွားတာကို verify လုပ်ရန်အတွက် `subscribed` command: ကိုသုံးပါ- + $user->subscription('main')->cancelNow(); - if ($user->subscribed()) - { - // - } + +### Resuming Subscriptions -`subscribed` method က Route filter အတွက် အကောင်းဆုံး အသင့်တော်ဆုံး လုပ်ဆောင်ပေးထားပါတယ်: +If a user has cancelled their subscription and you wish to resume it, use the `resume` method. The user **must** still be on their grace period in order to resume a subscription: + $user->subscription('main')->resume(); - Route::filter('subscribed', function() - { - if (Auth::user() && ! Auth::user()->subscribed()) - { - return Redirect::to('billing'); - } - }); +If the user cancels a subscription and then resumes that subscription before the subscription has fully expired, they will not be billed immediately. Instead, their subscription will simply be re-activated, and they will be billed on the original billing cycle. -သင့်အနေနဲ့ user က trial ကာလမှာဟုတ်မဟုတ်ကို `onTrial` method ကိုအသုံးပြုပြီးတော့ ဆုံးဖြတ်ပေးနိုင်ပါတယ်: + +### Updating Credit Cards - if ($user->onTrial()) - { - // - } +The `updateCard` method may be used to update a customer's credit card information. This method accepts a Stripe token and will assign the new credit card as the default billing source: -သင့်အနေနဲ့ user က active subscriber လား ဒါမှမဟုတ် cancel လုပ်လိုက်ပြီလားဆိုတာကို `cancelled` method ကိုသုံးပြီးတော့စစ်နိုင်ပါတယ်: + $user->updateCard($stripeToken); + +## Subscription Trials - if ($user->cancelled()) - { - // - } + +### With Credit Card Up Front -သင့်အနေနဲ့ User ကသူ့ရဲ့ subscription ကို cancel လုပ်လိုက်ပြီ ဒါပေမယ့် subscription ကလည်း fully expires မဖြစ်သေးဘူး... တစ်နည်းအားဖြင့် "grace period" လည်းမကုန်သေးဘူးဆိုတာကို ဆုံးဖြတ်နိုင်ပါတယ်။ ဥပမာ၊ user က subscription ကို March လ 5 ရက်နေ့မှာ cancel လုပ်လိုက်တယ်... တကယ်တမ်း scheduled မှာက March လ 10 ရက်နေ့မှပြီးမယ်ဆိုရင် အဲ့ဒီ့ user က "grace period" မှာဘဲရှိသေးပါတယ်။ မှတ်ထားရမှာက `subscribed` method ကအဲ့ဒီ့အချိန်မှာ `true` return ဘဲပြန်နေဦးမှာပါ။ +If you would like to offer trial periods to your customers while still collecting payment method information up front, You should use the `trialDays` method when creating your subscriptions: - if ($user->onGracePeriod()) - { - // - } + $user = User::find(1); -User က သင့် application ရဲ့ plan တစ်ခုကိုအမြဲတမ်း subscribed လုပ်ပြီးပြီလား မလုပ်ရသေးဘူးလားဆိုတာကို `everSubscribed` method နဲ့ စစ်ဆေးနိုင်ပါတယ်: + $user->newSubscription('main', 'monthly') + ->trialDays(10) + ->create($stripeToken); - if ($user->everSubscribed()) - { - // - } +This method will set the trial period ending date on the subscription record within the database, as well as instruct Stripe / Braintree to not begin billing the customer until after this date. - -## Handling Failed Payments +> {note} If the customer's subscription is not cancelled before the trial ending date they will be charged as soon as the trial expires, so you should be sure to notify your users of their trial ending date. -ကတယ်လို့ customer ရဲ့ credit card expires ဖြစ်နေရင်လား၊ မစိုးရိမ်ပါနဲ့ Cashuer က Webhook controller တစ်ခုပါဝင်ပါတယ်... အဲဒါကဘာလုပ်နိုင်လဲဆိုရင် customer ရဲ့ subscriotion ကို သင့်အတွက် cancel လုပ်ပေးပါလိမ့်မယ်: +You may determine if the user is within their trial period using either the `onTrial` method of the user instance, or the `onTrial` method of the subscription instance. The two examples below are identical: - Route::post('stripe/webhook', 'Laravel\Cashier\WebhookController@handleWebhook'); + if ($user->onTrial('main')) { + // + } -ဒါဘဲလေ။ Payment Fail ဖြစ်တာတွေ capture လုပ်တာတွေကိုလည်း controller ကဖြေရှင်းပေးပါလိမ့်မယ်။ controller က payment သုံးကြိမ်ကြိုးစားလို့မှမရဘူးဆိုရင် customer subscription ကို cancel လုပ်ပါလိမ့်မယ်။ ဒီဥပမာမှာ `stripe/webbhook` URI က ဥပမာအတွက်ပါ။ သင့်အနေနဲ့အဲ့ဒီ့ URI ကို Stripe Setting မှာ configure လုပ်ဖို့လိုမှာပါ။ + if ($user->subscription('main')->onTrial()) { + // + } -သင်ထက်ပေါင်းထည့်ထားတဲ့ Stripe webhook event ကိုဖြေရှင်းချင်တယ်ဆိုရင် Webhook controller ကို ရိုးရှင်းစွာဘဲ extend လုပ်လိုက်ပါ : + +### Without Credit Card Up Front - class WebhookController extends Laravel\Cashier\WebhookController { +If you would like to offer trial periods without collecting the user's payment method information up front, you may simply set the `trial_ends_at` column on the user record to your desired trial ending date. This is typically done during user registration: - public function handleWebhook() - { - // Handle other events... + $user = User::create([ + // Populate other user properties... + 'trial_ends_at' => Carbon::now()->addDays(10), + ]); - // Fallback to failed payment check... - return parent::handleWebhook(); - } +> {note} Be sure to add a [date mutator](/docs/{{version}}/eloquent-mutators#date-mutators) for `trial_ends_at` to your model definition. - } +Cashier refers to this type of trial as a "generic trial", since it is not attached to any existing subscription. The `onTrial` method on the `User` instance will return `true` if the current date is not past the value of `trial_ends_at`: -> **Note:** In addition to updating the subscription information in your database, the Webhook controller will also cancel the subscription via the Stripe API. + if ($user->onTrial()) { + // User is within their trial period... + } + +You may also use the `onGenericTrial` method if you wish to know specifically that the user is within their "generic" trial period and has not created an actual subscription yet: + + if ($user->onGenericTrial()) { + // User is within their "generic" trial period... + } + +Once you are ready to create an actual subscription for the user, you may use the `newSubscription` method as usual: + + $user = User::find(1); + + $user->newSubscription('main', 'monthly')->create($stripeToken); + + +## Handling Stripe Webhooks + +Both Stripe and Braintree can notify your application of a variety of events via webhooks. To handle Stripe webhooks, define a route that points to Cashier's webhook controller. This controller will handle all incoming webhook requests and dispatch them to the proper controller method: + + Route::post( + 'stripe/webhook', + '\Laravel\Cashier\Http\Controllers\WebhookController@handleWebhook' + ); + +> {note} Once you have registered your route, be sure to configure the webhook URL in your Stripe control panel settings. + +By default, this controller will automatically handle cancelling subscriptions that have too many failed charges (as defined by your Stripe settings); however, as we'll soon discover, you can extend this controller to handle any webhook event you like. + +#### Webhooks & CSRF Protection + +Since Stripe webhooks need to bypass Laravel's [CSRF protection](/docs/{{version}}/csrf), be sure to list the URI as an exception in your `VerifyCsrfToken` middleware or list the route outside of the `web` middleware group: + + protected $except = [ + 'stripe/*', + ]; + + +### Defining Webhook Event Handlers + +Cashier automatically handles subscription cancellation on failed charges, but if you have additional Stripe webhook events you would like to handle, simply extend the Webhook controller. Your method names should correspond to Cashier's expected convention, specifically, methods should be prefixed with `handle` and the "camel case" name of the Stripe webhook you wish to handle. For example, if you wish to handle the `invoice.payment_succeeded` webhook, you should add a `handleInvoicePaymentSucceeded` method to the controller: + + +### Failed Subscriptions + +What if a customer's credit card expires? No worries - Cashier includes a Webhook controller that can easily cancel the customer's subscription for you. As noted above, all you need to do is point a route to the controller: + + Route::post( + 'stripe/webhook', + '\Laravel\Cashier\Http\Controllers\WebhookController@handleWebhook' + ); + +That's it! Failed payments will be captured and handled by the controller. The controller will cancel the customer's subscription when Stripe determines the subscription has failed (normally after three failed payment attempts). + + +## Handling Braintree Webhooks + +Both Stripe and Braintree can notify your application of a variety of events via webhooks. To handle Braintree webhooks, define a route that points to Cashier's webhook controller. This controller will handle all incoming webhook requests and dispatch them to the proper controller method: + + Route::post( + 'braintree/webhook', + '\Laravel\Cashier\Http\Controllers\WebhookController@handleWebhook' + ); + +> {note} Once you have registered your route, be sure to configure the webhook URL in your Braintree control panel settings. + +By default, this controller will automatically handle cancelling subscriptions that have too many failed charges (as defined by your Braintree settings); however, as we'll soon discover, you can extend this controller to handle any webhook event you like. + +#### Webhooks & CSRF Protection + +Since Braintree webhooks need to bypass Laravel's [CSRF protection](/docs/{{version}}/csrf), be sure to list the URI as an exception in your `VerifyCsrfToken` middleware or list the route outside of the `web` middleware group: + + protected $except = [ + 'braintree/*', + ]; + + +### Defining Webhook Event Handlers + +Cashier automatically handles subscription cancellation on failed charges, but if you have additional Braintree webhook events you would like to handle, simply extend the Webhook controller. Your method names should correspond to Cashier's expected convention, specifically, methods should be prefixed with `handle` and the "camel case" name of the Braintree webhook you wish to handle. For example, if you wish to handle the `dispute_opened` webhook, you should add a `handleDisputeOpened` method to the controller: + + +### Failed Subscriptions + +What if a customer's credit card expires? No worries - Cashier includes a Webhook controller that can easily cancel the customer's subscription for you. Just point a route to the controller: + + Route::post( + 'braintree/webhook', + '\Laravel\Cashier\Http\Controllers\WebhookController@handleWebhook' + ); + +That's it! Failed payments will be captured and handled by the controller. The controller will cancel the customer's subscription when Braintree determines the subscription has failed (normally after three failed payment attempts). Don't forget: you will need to configure the webhook URI in your Braintree control panel settings. + + +## Single Charges + +### Simple Charge + +> {note} When using Stripe, the `charge` method accepts the amount you would like to charge in the **lowest denominator of the currency used by your application**. However, when using Braintree, you should pass the full dollar amount to the `charge` method: + +If you would like to make a "one off" charge against a subscribed customer's credit card, you may use the `charge` method on a billable model instance. + + // Stripe Accepts Charges In Cents... + $user->charge(100); + + // Braintree Accepts Charges In Dollars... + $user->charge(1); + +The `charge` method accepts an array as its second argument, allowing you to pass any options you wish to the underlying Stripe / Braintree charge creation. Consult the Stripe or Braintree documentation regarding the options available to you when creating charges: + + $user->charge(100, [ + 'custom_option' => $value, + ]); + +The `charge` method will throw an exception if the charge fails. If the charge is successful, the full Stripe / Braintree response will be returned from the method: + + try { + $response = $user->charge(100); + } catch (Exception $e) { + // + } + +### Charge With Invoice + +Sometimes you may need to make a one-time charge but also generate an invoice for the charge so that you may offer a PDF receipt to your customer. The `invoiceFor` method lets you do just that. For example, let's invoice the customer $5.00 for a "One Time Fee": + + // Stripe Accepts Charges In Cents... + $user->invoiceFor('One Time Fee', 500); + + // Braintree Accepts Charges In Dollars... + $user->invoiceFor('One Time Fee', 5); + +The invoice will be charged immediately against the user's credit card. The `invoiceFor` method also accepts an array as its third argument, allowing you to pass any options you wish to the underlying Stripe / Braintree charge creation: + + $user->invoiceFor('One Time Fee', 500, [ + 'custom-option' => $value, + ]); + +> {note} The `invoiceFor` method will create a Stripe invoice which will retry failed billing attempts. If you do not want invoices to retry failed charges, you will need to close them using the Stripe API after the first failed charge. ## Invoices -သင့်အနေနဲ့ user invoices ရဲ့ array ကို `invoices` method ကိုသုံးပြီးတော့ လွယ်လွယ်ကူကူ retrieve လုပ်နိုင်ပါတယ်: +You may easily retrieve an array of a billable model's invoices using the `invoices` method: + + $invoices = $user->invoices(); + + // Include pending invoices in the results... + $invoices = $user->invoicesIncludingPending(); + +When listing the invoices for the customer, you may use the invoice's helper methods to display the relevant invoice information. For example, you may wish to list every invoice in a table, allowing the user to easily download any of them: - $invoices = $user->invoices(); + + @foreach ($invoices as $invoice) + + + + + + @endforeach +
    {{ $invoice->date()->toFormattedDateString() }}{{ $invoice->total() }}Download
    -Customer တွေရဲ့ invoices တွေကို List လုပ်တဲ့အချိန်မှာ သင့်အနေနဲ့ invoice information နဲ့ပတ်သတ်တာတွေကို ပြသဖို့ရာအတွက် ဒီ helper တွေကို သုံးနိုင်ပါတယ်: + +### Generating Invoice PDFs - {{ $invoice->id }} +Before generating invoice PDFs, you need to install the `dompdf` PHP library: - {{ $invoice->dateString() }} + composer require dompdf/dompdf - {{ $invoice->dollars() }} +Then, from within a route or controller, use the `downloadInvoice` method to generate a PDF download of the invoice. This method will automatically generate the proper HTTP response to send the download to the browser: -Invoice PDF download ကို generate ထုတ်ဖို့ရာအတွက် `downloadInvoice` method ကိုသုံးပါ။ ဟုတ်တယ်...ဒါကတကယ်ကိုလွယ်ပါတယ်: + use Illuminate\Http\Request; - return $user->downloadInvoice($invoice->id, [ - 'vendor' => 'Your Company', - 'product' => 'Your Product', - ]); \ No newline at end of file + Route::get('user/invoice/{invoice}', function (Request $request, $invoiceId) { + return $request->user()->downloadInvoice($invoiceId, [ + 'vendor' => 'Your Company', + 'product' => 'Your Product', + ]); + }); diff --git a/blade.md b/blade.md new file mode 100644 index 0000000..ebd3e10 --- /dev/null +++ b/blade.md @@ -0,0 +1,428 @@ +# Blade Templates + +- [Introduction](#introduction) +- [Template Inheritance](#template-inheritance) + - [Defining A Layout](#defining-a-layout) + - [Extending A Layout](#extending-a-layout) +- [Components & Slots](#components-and-slots) +- [Displaying Data](#displaying-data) + - [Blade & JavaScript Frameworks](#blade-and-javascript-frameworks) +- [Control Structures](#control-structures) + - [If Statements](#if-statements) + - [Loops](#loops) + - [The Loop Variable](#the-loop-variable) + - [Comments](#comments) + - [PHP](#php) +- [Including Sub-Views](#including-sub-views) + - [Rendering Views For Collections](#rendering-views-for-collections) +- [Stacks](#stacks) +- [Service Injection](#service-injection) +- [Extending Blade](#extending-blade) + + +## Introduction + +Blade is the simple, yet powerful templating engine provided with Laravel. Unlike other popular PHP templating engines, Blade does not restrict you from using plain PHP code in your views. In fact, all Blade views are compiled into plain PHP code and cached until they are modified, meaning Blade adds essentially zero overhead to your application. Blade view files use the `.blade.php` file extension and are typically stored in the `resources/views` directory. + + +## Template Inheritance + + +### Defining A Layout + +Two of the primary benefits of using Blade are _template inheritance_ and _sections_. To get started, let's take a look at a simple example. First, we will examine a "master" page layout. Since most web applications maintain the same general layout across various pages, it's convenient to define this layout as a single Blade view: + + + + + + App Name - @yield('title') + + + @section('sidebar') + This is the master sidebar. + @show + +
    + @yield('content') +
    + + + +As you can see, this file contains typical HTML mark-up. However, take note of the `@section` and `@yield` directives. The `@section` directive, as the name implies, defines a section of content, while the `@yield` directive is used to display the contents of a given section. + +Now that we have defined a layout for our application, let's define a child page that inherits the layout. + + +### Extending A Layout + +When defining a child view, use the Blade `@extends` directive to specify which layout the child view should "inherit". Views which extend a Blade layout may inject content into the layout's sections using `@section` directives. Remember, as seen in the example above, the contents of these sections will be displayed in the layout using `@yield`: + + + + @extends('layouts.app') + + @section('title', 'Page Title') + + @section('sidebar') + @@parent + +

    This is appended to the master sidebar.

    + @endsection + + @section('content') +

    This is my body content.

    + @endsection + +In this example, the `sidebar` section is utilizing the `@@parent` directive to append (rather than overwriting) content to the layout's sidebar. The `@@parent` directive will be replaced by the content of the layout when the view is rendered. + +Blade views may be returned from routes using the global `view` helper: + + Route::get('blade', function () { + return view('child'); + }); + + +## Components & Slots + +Components and slots provide similar benefits to sections and layouts; however, some may find the mental model of components and slots easier to understand. First, let's imagine a reusable "alert" component we would like to reuse throughout our application: + + + +
    + {{ $slot }} +
    + +The `{{ $slot }}` variable will contain the content we wish to inject into the component. Now, to construct this component, we can use the `@component` Blade directive: + + @component('alert') + Whoops! Something went wrong! + @endcomponent + +Sometimes it is helpful to define multiple slots for a component. Let's modify our alert component to allow for the injection of a "title". Named slots may be displayed by simply "echoing" the variable that matches their name: + + + +
    +
    {{ $title }}
    + + {{ $slot }} +
    + +Now, we can inject content into the named slot using the `@slot` directive. Any content not within a `@slot` directive will be passed to the component in the `$slot` variable: + + @component('alert') + @slot('title') + Forbidden + @endslot + + You are not allowed to access this resource! + @endcomponent + +#### Passing Additional Data To Components + +Sometimes you may need to pass additional data to a component. For this reason, you can pass an array of data as the second argument to the `@component` directive. All of the data will be made available to the component template as variables: + + @component('alert', ['foo' => 'bar']) + ... + @endcomponent + + +## Displaying Data + +You may display data passed to your Blade views by wrapping the variable in curly braces. For example, given the following route: + + Route::get('greeting', function () { + return view('welcome', ['name' => 'Samantha']); + }); + +You may display the contents of the `name` variable like so: + + Hello, {{ $name }}. + +Of course, you are not limited to displaying the contents of the variables passed to the view. You may also echo the results of any PHP function. In fact, you can put any PHP code you wish inside of a Blade echo statement: + + The current UNIX timestamp is {{ time() }}. + +> {note} Blade `{{ }}` statements are automatically sent through PHP's `htmlentities` function to prevent XSS attacks. + +#### Echoing Data If It Exists + +Sometimes you may wish to echo a variable, but you aren't sure if the variable has been set. We can express this in verbose PHP code like so: + + {{ isset($name) ? $name : 'Default' }} + +However, instead of writing a ternary statement, Blade provides you with the following convenient shortcut, which will be compiled to the ternary statement above: + + {{ $name or 'Default' }} + +In this example, if the `$name` variable exists, its value will be displayed. However, if it does not exist, the word `Default` will be displayed. + +#### Displaying Unescaped Data + +By default, Blade `{{ }}` statements are automatically sent through PHP's `htmlentities` function to prevent XSS attacks. If you do not want your data to be escaped, you may use the following syntax: + + Hello, {!! $name !!}. + +> {note} Be very careful when echoing content that is supplied by users of your application. Always use the escaped, double curly brace syntax to prevent XSS attacks when displaying user supplied data. + + +### Blade & JavaScript Frameworks + +Since many JavaScript frameworks also use "curly" braces to indicate a given expression should be displayed in the browser, you may use the `@` symbol to inform the Blade rendering engine an expression should remain untouched. For example: + +

    Laravel

    + + Hello, @{{ name }}. + +In this example, the `@` symbol will be removed by Blade; however, `{{ name }}` expression will remain untouched by the Blade engine, allowing it to instead be rendered by your JavaScript framework. + +#### The `@verbatim` Directive + +If you are displaying JavaScript variables in a large portion of your template, you may wrap the HTML in the `@verbatim` directive so that you do not have to prefix each Blade echo statement with an `@` symbol: + + @verbatim +
    + Hello, {{ name }}. +
    + @endverbatim + + +## Control Structures + +In addition to template inheritance and displaying data, Blade also provides convenient shortcuts for common PHP control structures, such as conditional statements and loops. These shortcuts provide a very clean, terse way of working with PHP control structures, while also remaining familiar to their PHP counterparts. + + +### If Statements + +You may construct `if` statements using the `@if`, `@elseif`, `@else`, and `@endif` directives. These directives function identically to their PHP counterparts: + + @if (count($records) === 1) + I have one record! + @elseif (count($records) > 1) + I have multiple records! + @else + I don't have any records! + @endif + +For convenience, Blade also provides an `@unless` directive: + + @unless (Auth::check()) + You are not signed in. + @endunless + + +### Loops + +In addition to conditional statements, Blade provides simple directives for working with PHP's loop structures. Again, each of these directives functions identically to their PHP counterparts: + + @for ($i = 0; $i < 10; $i++) + The current value is {{ $i }} + @endfor + + @foreach ($users as $user) +

    This is user {{ $user->id }}

    + @endforeach + + @forelse ($users as $user) +
  • {{ $user->name }}
  • + @empty +

    No users

    + @endforelse + + @while (true) +

    I'm looping forever.

    + @endwhile + +> {tip} When looping, you may use the [loop variable](#the-loop-variable) to gain valuable information about the loop, such as whether you are in the first or last iteration through the loop. + +When using loops you may also end the loop or skip the current iteration: + + @foreach ($users as $user) + @if ($user->type == 1) + @continue + @endif + +
  • {{ $user->name }}
  • + + @if ($user->number == 5) + @break + @endif + @endforeach + +You may also include the condition with the directive declaration in one line: + + @foreach ($users as $user) + @continue($user->type == 1) + +
  • {{ $user->name }}
  • + + @break($user->number == 5) + @endforeach + + +### The Loop Variable + +When looping, a `$loop` variable will be available inside of your loop. This variable provides access to some useful bits of information such as the current loop index and whether this is the first or last iteration through the loop: + + @foreach ($users as $user) + @if ($loop->first) + This is the first iteration. + @endif + + @if ($loop->last) + This is the last iteration. + @endif + +

    This is user {{ $user->id }}

    + @endforeach + +If you are in a nested loop, you may access the parent loop's `$loop` variable via the `parent` property: + + @foreach ($users as $user) + @foreach ($user->posts as $post) + @if ($loop->parent->first) + This is first iteration of the parent loop. + @endif + @endforeach + @endforeach + +The `$loop` variable also contains a variety of other useful properties: + +Property | Description +------------- | ------------- +`$loop->index` | The index of the current loop iteration (starts at 0). +`$loop->iteration` | The current loop iteration (starts at 1). +`$loop->remaining` | The iteration remaining in the loop. +`$loop->count` | The total number of items in the array being iterated. +`$loop->first` | Whether this is the first iteration through the loop. +`$loop->last` | Whether this is the last iteration through the loop. +`$loop->depth` | The nesting level of the current loop. +`$loop->parent` | When in a nested loop, the parent's loop variable. + + +### Comments + +Blade also allows you to define comments in your views. However, unlike HTML comments, Blade comments are not included in the HTML returned by your application: + + {{-- This comment will not be present in the rendered HTML --}} + + +### PHP + +In some situations, it's useful to embed PHP code into your views. You can use the Blade `@php` directive to execute a block of plain PHP within your template: + + @php + // + @endphp + +> {tip} While Blade provides this feature, using it frequently may be a signal that you have too much logic embedded within your template. + + +## Including Sub-Views + +Blade's `@include` directive allows you to include a Blade view from within another view. All variables that are available to the parent view will be made available to the included view: + +
    + @include('shared.errors') + +
    + +
    +
    + +Even though the included view will inherit all data available in the parent view, you may also pass an array of extra data to the included view: + + @include('view.name', ['some' => 'data']) + +Of course, if you attempt to `@include` a view which does not exist, Laravel will throw an error. If you would like to include a view that may or may not be present, you should use the `@includeIf` directive: + + @includeIf('view.name', ['some' => 'data']) + +> {note} You should avoid using the `__DIR__` and `__FILE__` constants in your Blade views, since they will refer to the location of the cached, compiled view. + + +### Rendering Views For Collections + +You may combine loops and includes into one line with Blade's `@each` directive: + + @each('view.name', $jobs, 'job') + +The first argument is the view partial to render for each element in the array or collection. The second argument is the array or collection you wish to iterate over, while the third argument is the variable name that will be assigned to the current iteration within the view. So, for example, if you are iterating over an array of `jobs`, typically you will want to access each job as a `job` variable within your view partial. The key for the current iteration will be available as the `key` variable within your view partial. + +You may also pass a fourth argument to the `@each` directive. This argument determines the view that will be rendered if the given array is empty. + + @each('view.name', $jobs, 'job', 'view.empty') + + +## Stacks + +Blade allows you to push to named stacks which can be rendered somewhere else in another view or layout. This can be particularly useful for specifying any JavaScript libraries required by your child views: + + @push('scripts') + + @endpush + +You may push to a stack as many times as needed. To render the complete stack contents, pass the name of the stack to the `@stack` directive: + + + + + @stack('scripts') + + + +## Service Injection + +The `@inject` directive may be used to retrieve a service from the Laravel [service container](/docs/{{version}}/container). The first argument passed to `@inject` is the name of the variable the service will be placed into, while the second argument is the class or interface name of the service you wish to resolve: + + @inject('metrics', 'App\Services\MetricsService') + +
    + Monthly Revenue: {{ $metrics->monthlyRevenue() }}. +
    + + +## Extending Blade + +Blade allows you to define your own custom directives using the `directive` method. When the Blade compiler encounters the custom directive, it will call the provided callback with the expression that the directive contains. + +The following example creates a `@datetime($var)` directive which formats a given `$var`, which should be an instance of `DateTime`: + + format('m/d/Y H:i'); ?>"; + }); + } + + /** + * Register bindings in the container. + * + * @return void + */ + public function register() + { + // + } + } + +As you can see, we will chain the `format` method onto whatever expression is passed into the directive. So, in this example, the final PHP generated by this directive will be: + + format('m/d/Y H:i'); ?> + +> {note} After updating the logic of a Blade directive, you will need to delete all of the cached Blade views. The cached Blade views may be removed using the `view:clear` Artisan command. diff --git a/broadcasting.md b/broadcasting.md new file mode 100644 index 0000000..596fff8 --- /dev/null +++ b/broadcasting.md @@ -0,0 +1,524 @@ +# Event Broadcasting + +- [Introduction](#introduction) + - [Configuration](#configuration) + - [Driver Prerequisites](#driver-prerequisites) +- [Concept Overview](#concept-overview) + - [Using An Example Application](#using-example-application) +- [Defining Broadcast Events](#defining-broadcast-events) + - [Broadcast Name](#broadcast-name) + - [Broadcast Data](#broadcast-data) + - [Broadcast Queue](#broadcast-queue) +- [Authorizing Channels](#authorizing-channels) + - [Defining Authorization Routes](#defining-authorization-routes) + - [Defining Authorization Callbacks](#defining-authorization-callbacks) +- [Broadcasting Events](#broadcasting-events) + - [Only To Others](#only-to-others) +- [Receiving Broadcasts](#receiving-broadcasts) + - [Installing Laravel Echo](#installing-laravel-echo) + - [Listening For Events](#listening-for-events) + - [Leaving A Channel](#leaving-a-channel) + - [Namespaces](#namespaces) +- [Presence Channels](#presence-channels) + - [Authorizing Presence Channels](#authorizing-presence-channels) + - [Joining Presence Channels](#joining-presence-channels) + - [Broadcasting To Presence Channels](#broadcasting-to-presence-channels) +- [Client Events](#client-events) +- [Notifications](#notifications) + + +## Introduction + +In many modern web applications, WebSockets are used to implement realtime, live-updating user interfaces. When some data is updated on the server, a message is typically sent over a WebSocket connection to be handled by the client. This provides a more robust, efficient alternative to continually polling your application for changes. + +To assist you in building these types of applications, Laravel makes it easy to "broadcast" your [events](/docs/{{version}}/events) over a WebSocket connection. Broadcasting your Laravel events allows you to share the same event names between your server-side code and your client-side JavaScript application. + +> {tip} Before diving into event broadcasting, make sure you have read all of the documentation regarding Laravel [events and listeners](/docs/{{version}}/events). + + +### Configuration + +All of your application's event broadcasting configuration is stored in the `config/broadcasting.php` configuration file. Laravel supports several broadcast drivers out of the box: [Pusher](https://pusher.com), [Redis](/docs/{{version}}/redis), and a `log` driver for local development and debugging. Additionally, a `null` driver is included which allows you to totally disable broadcasting. A configuration example is included for each of these drivers in the `config/broadcasting.php` configuration file. + +#### Broadcast Service Provider + +Before broadcasting any events, you will first need to register the `App\Providers\BroadcastServiceProvider`. In fresh Laravel applications, you only need to uncomment this provider in the `providers` array of your `config/app.php` configuration file. This provider will allow you to register the broadcast authorization routes and callbacks. + +#### CSRF Token + +[Laravel Echo](#installing-laravel-echo) will need access to the current session's CSRF token. If available, Echo will pull the token from the `Laravel.csrfToken` JavaScript object. This object is defined in the `resources/views/layouts/app.blade.php` layout that is created if you run the `make:auth` Artisan command. If you are not using this layout, you may define a `meta` tag in your application's `head` HTML element: + + + + +### Driver Prerequisites + +#### Pusher + +If you are broadcasting your events over [Pusher](https://pusher.com), you should install the Pusher PHP SDK using the Composer package manager: + + composer require pusher/pusher-php-server + +Next, you should configure your Pusher credentials in the `config/broadcasting.php` configuration file. An example Pusher configuration is already included in this file, allowing you to quickly specify your Pusher key, secret, and application ID. The `config/broadcasting.php` file's `pusher` configuration also allows you to specify additional `options` that are supported by Pusher, such as the cluster: + + 'options' => [ + 'cluster' => 'eu', + 'encrypted' => true + ], + +When using Pusher and [Laravel Echo](#installing-laravel-echo), you should specify `pusher` as your desired broadcaster when instantiating the Echo instance in your `resources/assets/js/bootstrap.js` file: + + import Echo from "laravel-echo" + + window.Echo = new Echo({ + broadcaster: 'pusher', + key: 'your-pusher-key' + }); + +#### Redis + +If you are using the Redis broadcaster, you should install the Predis library: + + composer require predis/predis + +The Redis broadcaster will broadcast messages using Redis' pub / sub feature; however, you will need to pair this with a WebSocket server that can receive the messages from Redis and broadcast them to your WebSocket channels. + +When the Redis broadcaster publishes an event, it will be published on the event's specified channel names and the payload will be a JSON encoded string containing the event name, a `data` payload, and the user that generated the event's socket ID (if applicable). + +#### Socket.IO + +If you are going to pair the Redis broadcaster with a Socket.IO server, you will need to include the Socket.IO JavaScript client library in your application's `head` HTML element. When the Socket.IO server is started, it will automatically expose the client JavaScript library at a standard URL. For example, if you are running the Socket.IO server on the same domain as your web application, you may access the client library like so: + + + +Next, you will need to instantiate Echo with the `socket.io` connector and a `host`. + + import Echo from "laravel-echo" + + window.Echo = new Echo({ + broadcaster: 'socket.io', + host: window.location.hostname + ':6001' + }); + +Finally, you will need to run a compatible Socket.IO server. Laravel does not include a Socket.IO server implementation; however, a community driven Socket.IO server is currently maintained at the [tlaverdure/laravel-echo-server](https://github.com/tlaverdure/laravel-echo-server) GitHub repository. + +#### Queue Prerequisites + +Before broadcasting events, you will also need to configure and run a [queue listener](/docs/{{version}}/queues). All event broadcasting is done via queued jobs so that the response time of your application is not seriously affected. + + +## Concept Overview + +Laravel's event broadcasting allows you to broadcast your server-side Laravel events to your client-side JavaScript application using a driver-based approach to WebSockets. Currently, Laravel ships with [Pusher](https://pusher.com) and Redis drivers. The events may be easily consumed on the client-side using the [Laravel Echo](#installing-laravel-echo) Javascript package. + +Events are broadcast over "channels", which may be specified as public or private. Any visitor to your application may subscribe to a public channel without any authentication or authorization; however, in order to subscribe to a private channel, a user must be authenticated and authorized to listen on that channel. + + +### Using An Example Application + +Before diving into each component of event broadcasting, let's take a high level overview using an e-commerce store as an example. We won't discuss the details of configuring [Pusher](https://pusher.com) or [Laravel Echo](#installing-laravel-echo) since that will be discussed in detail in other sections of this documentation. + +In our application, let's assume we have a page that allows users to view the shipping status for their orders. Let's also assume that a `ShippingStatusUpdated` event is fired when a shipping status update is processed by the application: + + event(new ShippingStatusUpdated($update)); + +#### The `ShouldBroadcast` Interface + +When a user is viewing one of their orders, we don't want them to have to refresh the page to view status updates. Instead, we want to broadcast the updates to the application as they are created. So, we need to mark the `ShippingStatusUpdated` event with the `ShouldBroadcast` interface. This will instruct Laravel to broadcast the event when it is fired: + + update->order_id); + } + +#### Authorizing Channels + +Remember, users must be authorized to listen on private channels. We may define our channel authorization rules in the `routes/channels.php` file. In this example, we need to verify that any user attempting to listen on the private `order.1` channel is actually the creator of the order: + + Broadcast::channel('order.{orderId}', function ($user, $orderId) { + return $user->id === Order::findOrNew($orderId)->user_id; + }); + +The `channel` method accepts two arguments: the name of the channel and a callback which returns `true` or `false` indicating whether the user is authorized to listen on the channel. + +All authorization callbacks receive the currently authenticated user as their first argument and any additional wildcard parameters as their subsequent arguments. In this example, we are using the `{orderId}` placeholder to indicate that the "ID" portion of the channel name is a wildcard. + +#### Listening For Event Broadcasts + +Next, all that remains is to listen for the event in our JavaScript application. We can do this using Laravel Echo. First, we'll use the `private` method to subscribe to the private channel. Then, we may use the `listen` method to listen for the `ShippingStatusUpdated` event. By default, all of the event's public properties will be included on the broadcast event: + + Echo.private(`order.${orderId}`) + .listen('ShippingStatusUpdated', (e) => { + console.log(e.update); + }); + + +## Defining Broadcast Events + +To inform Laravel that a given event should be broadcast, implement the `Illuminate\Contracts\Broadcasting\ShouldBroadcast` interface on the event class. This interface is already imported into all event classes generated by the framework so you may easily add it to any of your events. + +The `ShouldBroadcast` interface requires you to implement a single method: `broadcastOn`. The `broadcastOn` method should return a channel or array of channels that the event should broadcast on. The channels should be instances of `Channel`, `PrivateChannel`, or `PresenceChannel`. Instances of `Channel` represent public channels that any user may subscribe to, while `PrivateChannels` and `PresenceChannels` represent private channels that require [channel authorization](#authorizing-channels): + + user = $user; + } + + /** + * Get the channels the event should broadcast on. + * + * @return Channel|array + */ + public function broadcastOn() + { + return new PrivateChannel('user.'.$this->user->id); + } + } + +Then, you only need to [fire the event](/docs/{{version}}/events) as you normally would. Once the event has been fired, a [queued job](/docs/{{version}}/queues) will automatically broadcast the event over your specified broadcast driver. + + +### Broadcast Name + +By default, Laravel will broadcast the event using the event's class name. However, you may customize the broadcast name by defining a `broadcastAs` method on the event: + + /** + * The event's broadcast name. + * + * @return string + */ + public function broadcastAs() + { + return 'server.created'; + } + + +### Broadcast Data + +When an event is broadcast, all of its `public` properties are automatically serialized and broadcast as the event's payload, allowing you to access any of its public data from your JavaScript application. So, for example, if your event has a single public `$user` property that contains an Eloquent model, the event's broadcast payload would be: + + { + "user": { + "id": 1, + "name": "Patrick Stewart" + ... + } + } + +However, if you wish to have more fine-grained control over your broadcast payload, you may add a `broadcastWith` method to your event. This method should return the array of data that you wish to broadcast as the event payload: + + /** + * Get the data to broadcast. + * + * @return array + */ + public function broadcastWith() + { + return ['id' => $this->user->id]; + } + + +### Broadcast Queue + +By default, each broadcast event is placed on the default queue for the default queue connection specified in your `queue.php` configuration file. You may customize the queue used by the broadcaster by defining a `broadcastQueue` property on your event class. This property should specify the name of the queue you wish to use when broadcasting: + + /** + * The name of the queue on which to place the event. + * + * @var string + */ + public $broadcastQueue = 'your-queue-name'; + + +## Authorizing Channels + +Private channels require you to authorize that the currently authenticated user can actually listen on the channel. This is accomplished by making an HTTP request to your Laravel application with the channel name and allowing your application to determine if the user can listen on that channel. When using [Laravel Echo](#installing-laravel-echo), the HTTP request to authorize subscriptions to private channels will be made automatically; however, you do need to define the proper routes to respond to these requests. + + +### Defining Authorization Routes + +Thankfully, Laravel makes it easy to define the routes to respond to channel authorization requests. In the `BroadcastServiceProvider` included with your Laravel application, you will see a call to the `Broadcast::routes` method. This method will register the `/broadcasting/auth` route to handle authorization requests: + + Broadcast::routes(); + +The `Broadcast::routes` method will automatically place its routes within the `web` middleware group; however, you may pass an array of route attributes to the method if you would like to customize the assigned attributes: + + Broadcast::routes($attributes); + + +### Defining Authorization Callbacks + +Next, we need to define the logic that will actually perform the channel authorization. This is done in the `routes/channels.php` file that is included with your application. In this file, you may use the `Broadcast::channel` method to register channel authorization callbacks: + + Broadcast::channel('order.{orderId}', function ($user, $orderId) { + return $user->id === Order::findOrNew($orderId)->user_id; + }); + +The `channel` method accepts two arguments: the name of the channel and a callback which returns `true` or `false` indicating whether the user is authorized to listen on the channel. + +All authorization callbacks receive the currently authenticated user as their first argument and any additional wildcard parameters as their subsequent arguments. In this example, we are using the `{orderId}` placeholder to indicate that the "ID" portion of the channel name is a wildcard. + +#### Authorization Callback Model Binding + +Just like HTTP routes, channel routes may also take advantage of implicit and explicit [route model binding](/docs/{{version}}/routing#route-model-binding). For example, instead of receiving the string or numeric order ID, you may request an actual `Order` model instance: + + use App\Order; + + Broadcast::channel('order.{order}', function ($user, Order $order) { + return $user->id === $order->user_id; + }); + + +## Broadcasting Events + +Once you have defined an event and marked it with the `ShouldBroadcast` interface, you only need to fire the event using the `event` function. The event dispatcher will notice that the event is marked with the `ShouldBroadcast` interface and will queue the event for broadcasting: + + event(new ShippingStatusUpdated($update)); + + +### Only To Others + +When building an application that utilizes event broadcasting, you may substitute the `event` function with the `broadcast` function. Like the `event` function, the `broadcast` function dispatches the event to your server-side listeners: + + broadcast(new ShippingStatusUpdated($update)); + +However, the `broadcast` function also exposes the `toOthers` method which allows you to exclude the current user from the broadcast's recipients: + + broadcast(new ShippingStatusUpdated($update))->toOthers(); + +To better understand when you may want to use the `toOthers` method, let's imagine a task list application where a user may create a new task by entering a task name. To create a task, your application might make a request to a `/task` end-point which broadcasts the task's creation and returns a JSON representation of the new task. When your JavaScript application receives the response from the end-point, it might directly insert the new task into its task list like so: + + axios.post('/task', task) + .then((response) => { + this.tasks.push(response.data); + }); + +However, remember that we also broadcast the task's creation. If your JavaScript application is listening for this event in order to add tasks to the task list, you will have duplicate tasks in your list: one from the end-point and one from the broadcast. + +You may solve this by using the `toOthers` method to instruct the broadcaster to not broadcast the event to the current user. + +#### Configuration + +When you initialize a Laravel Echo instance, a socket ID is assigned to the connection. If you are using [Vue](https://vuejs.org) and [Axios](https://github.com/mzabriskie/axios), the socket ID will automatically be attached to every outgoing request as a `X-Socket-ID` header. Then, when you call the `toOthers` method, Laravel will extract the socket ID from the header and instruct the broadcaster to not broadcast to any connections with that socket ID. + +If you are not using Vue and Axios, you will need to manually configure your JavaScript application to send the `X-Socket-ID` header. You may retrieve the socket ID using the `Echo.socketId` method: + + var socketId = Echo.socketId(); + + +## Receiving Broadcasts + + +### Installing Laravel Echo + +Laravel Echo is a JavaScript library that makes it painless to subscribe to channels and listen for events broadcast by Laravel. You may install Echo via the NPM package manager. In this example, we will also install the `pusher-js` package since we will be using the Pusher broadcaster: + + npm install --save laravel-echo pusher-js + +Once Echo is installed, you are ready to create a fresh Echo instance in your application's JavaScript. A great place to do this is at the bottom of the `resources/assets/js/bootstrap.js` file that is included with the Laravel framework: + + import Echo from "laravel-echo" + + window.Echo = new Echo({ + broadcaster: 'pusher', + key: 'your-pusher-key' + }); + +When creating an Echo instance that uses the `pusher` connector, you may also specify a `cluster` as well as whether the connection should be encrypted: + + window.Echo = new Echo({ + broadcaster: 'pusher', + key: 'your-pusher-key', + cluster: 'eu', + encrypted: true + }); + + +### Listening For Events + +Once you have installed and instantiated Echo, you are ready to start listening for event broadcasts. First, use the `channel` method to retrieve an instance of a channel, then call the `listen` method to listen for a specified event: + + Echo.channel('orders') + .listen('OrderShipped', (e) => { + console.log(e.order.name); + }); + +If you would like to listen for events on a private channel, use the `private` method instead. You may continue to chain calls to the `listen` method to listen for multiple events on a single channel: + + Echo.private('orders') + .listen(...) + .listen(...) + .listen(...); + + +### Leaving A Channel + +To leave a channel, you may call the `leave` method on your Echo instance: + + Echo.leave('orders'); + + +### Namespaces + +You may have noticed in the examples above that we did not specify the full namespace for the event classes. This is because Echo will automatically assume the events are located in the `App\Events` namespace. However, you may configure the root namespace when you instantiate Echo by passing a `namespace` configuration option: + + window.Echo = new Echo({ + broadcaster: 'pusher', + key: 'your-pusher-key', + namespace: 'App.Other.Namespace' + }); + +Alternatively, you may prefix event classes with a `.` when subscribing to them using Echo. This will allow you to always specify the fully-qualified class name: + + Echo.channel('orders') + .listen('.Namespace.Event.Class', (e) => { + // + }); + + +## Presence Channels + +Presence channels build on the security of private channels while exposing the additional feature of awareness of who is subscribed to the channel. This makes it easy to build powerful, collaborative application features such as notifying users when another user is viewing the same page. + + +### Authorizing Presence Channels + +All presence channels are also private channels; therefore, users must be [authorized to access them](#authorizing-channels). However, when defining authorization callbacks for presence channels, you will not return `true` if the user is authorized to join the channel. Instead, you should return an array of data about the user. + +The data returned by the authorization callback will be made available to the presence channel event listeners in your JavaScript application. If the user is not authorized to join the presence channel, you should return `false` or `null`: + + Broadcast::channel('chat.*', function ($user, $roomId) { + if ($user->canJoinRoom($roomId)) { + return ['id' => $user->id, 'name' => $user->name]; + } + }); + + +### Joining Presence Channels + +To join a presence channel, you may use Echo's `join` method. The `join` method will return a `PresenceChannel` implementation which, along with exposing the `listen` method, allows you to subscribe to the `here`, `joining`, and `leaving` events. + + Echo.join(`chat.${roomId}`) + .here((users) => { + // + }) + .joining((user) => { + console.log(user.name); + }) + .leaving((user) => { + console.log(user.name); + }); + +The `here` callback will be executed immediately once the channel is joined successfully, and will receive an array containing the user information for all of the other users currently subscribed to the channel. The `joining` method will be executed when a new user joins a channel, while the `leaving` method will be executed when a user leaves the channel. + + +### Broadcasting To Presence Channels + +Presence channels may receive events just like public or private channels. Using the example of a chatroom, we may want to broadcast `NewMessage` events to the room's presence channel. To do so, we'll return an instance of `PresenceChannel` from the event's `broadcastOn` method: + + /** + * Get the channels the event should broadcast on. + * + * @return Channel|array + */ + public function broadcastOn() + { + return new PresenceChannel('room.'.$this->message->room_id); + } + +Like public or private events, presence channel events may be broadcast using the `broadcast` function. As with other events, you may use the `toOthers` method to exclude the current user from receiving the broadcast: + + broadcast(new NewMessage($message)); + + broadcast(new NewMessage($message))->toOthers(); + +You may listen for the join event via Echo's `listen` method: + + Echo.join(`chat.${roomId}`) + .here(...) + .joining(...) + .leaving(...) + .listen('NewMessage', (e) => { + // + }); + + +## Client Events + +Sometimes you may wish to broadcast an event to other connected clients without hitting your Laravel application at all. This can be particularly useful for things like "typing" notifications, where you want to alert users of your application that another user is typing a message on a given screen. To broadcast client events, you may use Echo's `whisper` method: + + Echo.channel('chat') + .whisper('typing', { + name: this.user.name + }); + +To listen for client events, you may use the `listenForWhisper` method: + + Echo.channel('chat') + .listenForWhisper('typing', (e) => { + console.log(e.name); + }); + + +## Notifications + +By pairing event broadcasting with [notifications](/docs/{{version}}/notifications), your JavaScript application may receive new notifications as they occur without needing to refresh the page. First, be sure to read over the documentation on using [the broadcast notification channel](/docs/{{version}}/notifications#broadcast-notifications). + +Once you have configured a notification to use the broadcast channel, you may listen for the broadcast events using Echo's `notification` method. Remember, the channel name should match the class name of the entity receiving the notifications: + + Echo.private(`App.User.${userId}`) + .notification((notification) => { + console.log(notification.type); + }); + +In this example, all notifications sent to `App\User` instances via the `broadcast` channel would be received by the callback. A channel authorization callback for the `App.User.{id}` channel is included in the default `BroadcastServiceProvider` that ships with the Laravel framework. diff --git a/cache.md b/cache.md index 9b14019..199f92d 100644 --- a/cache.md +++ b/cache.md @@ -1,142 +1,350 @@ # Cache -- [ပြင်ဆင်ခြင်း](#configuration) -- [Cache အသုံးပြုသည့်ပုံစံ](#cache-usage) -- [တန်ဖိုး ထပ်တိုးခြင်း နှင့် လျော့ချခြင်း](#increments-and-decrements) -- [Cache များအား အုပ်စုဖွဲ့ခြင်း](#cache-tags) -- [Database Cache](#database-cache) +- [Configuration](#configuration) + - [Driver Prerequisites](#driver-prerequisites) +- [Cache Usage](#cache-usage) + - [Obtaining A Cache Instance](#obtaining-a-cache-instance) + - [Retrieving Items From The Cache](#retrieving-items-from-the-cache) + - [Storing Items In The Cache](#storing-items-in-the-cache) + - [Removing Items From The Cache](#removing-items-from-the-cache) + - [The Cache Helper](#the-cache-helper) +- [Cache Tags](#cache-tags) + - [Storing Tagged Cache Items](#storing-tagged-cache-items) + - [Accessing Tagged Cache Items](#accessing-tagged-cache-items) + - [Removing Tagged Cache Items](#removing-tagged-cache-items) +- [Adding Custom Cache Drivers](#adding-custom-cache-drivers) + - [Writing The Driver](#writing-the-driver) + - [Registering The Driver](#registering-the-driver) +- [Events](#events) -## ပြင်ဆင်ခြင်း +## Configuration -Caching ပြုလုပ်နည်းပုံစံမျိုးစုံတွက် Laravel မှ API ထုတ်ပေးပြီးသားဖြစ်ပါတယ်။ Cache configuration အတွက် `app/config/cache.php` ဖိုင်ထဲမှာသွားပြင်ရမှာပါ။ Application တစ်ခုလုံးအတွက်အသုံးပြုမဲ့ cache driver ကို အဲ့ဒီဖိုင်ထဲမှာ သတ်မှတ်ပေးရမှာပါ။ [Memcached](http://memcached.org) နှင့် [Redis](http://redis.io) ကဲ့သိုသော လူသုံးများပြီး popular ဖြစ်တဲ့ caching methods တွေကို laravel မှာ အထောက်အပံ့ပေးထားပါတယ်။ +Laravel provides an expressive, unified API for various caching backends. The cache configuration is located at `config/cache.php`. In this file you may specify which cache driver you would like used by default throughout your application. Laravel supports popular caching backends like [Memcached](https://memcached.org) and [Redis](http://redis.io) out of the box. -အဲ့ဒီ cache configuration ဖိုင်ထဲမှာ ကျန်တဲ့ options တွေလဲ အများကြီးရှိပါသေးတယ်။ အဲ့ဒီအတွက်လဲ ဖိုင်ထဲမှာ တစ်ခါတည်း လမ်းညွှန်ချက်ရေးပေးထားပြီးသားပါ။ အကယ်၍ အဲ့ဒီ options တွေကိုအသုံးပြုမယ်ဆိုရင်တော့ option နဲ့ပတ်သက်တဲ့လမ်းညွှန်ချက်ကို သေသေချာချာဖတ်ပြီးမှ အသုံးပြုဖို့လိုအပ်ပါတယ်။ ပုံမှန်အတိုင်းဆိုရင်တော့ laravel ဟာ `file` cache driver အတွက် ပြင်ဆင်ပေးထားပါတယ်။ အဲ့ဒီ cache ဖိုင် objects တွေကို နံပါတ်စဉ်အတိုင်း filesystem ထဲမှာသွားသိမ်းထားပါတယ်။ Application အကြီးတွေအတွက်ဆိုရင်တော့ Memcached သို့မဟုတ် APC (Alternative PHP Cache) ကဲ့သို့သော in-memory cache တွေကိုအသုံးပြုသင့်ပါတယ်။ +The cache configuration file also contains various other options, which are documented within the file, so make sure to read over these options. By default, Laravel is configured to use the `file` cache driver, which stores the serialized, cached objects in the filesystem. For larger applications, it is recommended that you use a more robust driver such as Memcached or Redis. You may even configure multiple cache configurations for the same driver. + + +### Driver Prerequisites + +#### Database + +When using the `database` cache driver, you will need to setup a table to contain the cache items. You'll find an example `Schema` declaration for the table below: + + Schema::create('cache', function ($table) { + $table->string('key')->unique(); + $table->text('value'); + $table->integer('expiration'); + }); + +> {tip} You may also use the `php artisan cache:table` Artisan command to generate a migration with the proper schema. + +#### Memcached + +Using the Memcached driver requires the [Memcached PECL package](https://pecl.php.net/package/memcached) to be installed. You may list all of your Memcached servers in the `config/cache.php` configuration file: + + 'memcached' => [ + [ + 'host' => '127.0.0.1', + 'port' => 11211, + 'weight' => 100 + ], + ], + +You may also set the `host` option to a UNIX socket path. If you do this, the `port` option should be set to `0`: + + 'memcached' => [ + [ + 'host' => '/var/run/memcached/memcached.sock', + 'port' => 0, + 'weight' => 100 + ], + ], + +#### Redis + +Before using a Redis cache with Laravel, you will need to either install the `predis/predis` package (~1.0) via Composer or install the PhpRedis PHP extension via PECL. + +For more information on configuring Redis, consult its [Laravel documentation page](/docs/{{version}}/redis#configuration). -## Cache အသုံးပြုသည့်ပုံစံ +## Cache Usage + + +### Obtaining A Cache Instance + +The `Illuminate\Contracts\Cache\Factory` and `Illuminate\Contracts\Cache\Repository` [contracts](/docs/{{version}}/contracts) provide access to Laravel's cache services. The `Factory` contract provides access to all cache drivers defined for your application. The `Repository` contract is typically an implementation of the default cache driver for your application as specified by your `cache` configuration file. + +However, you may also use the `Cache` facade, which is what we will use throughout this documentation. The `Cache` facade provides convenient, terse access to the underlying implementations of the Laravel cache contracts: + + get('foo'); + + Cache::store('redis')->put('bar', 'baz', 10); + + +### Retrieving Items From The Cache + +The `get` method on the `Cache` facade is used to retrieve items from the cache. If the item does not exist in the cache, `null` will be returned. If you wish, you may pass a second argument to the `get` method specifying the default value you wish to be returned if the item doesn't exist: -#### အချက်အလက်ကို Cache ထဲတွင်သိမ်းဆည်းခြင်း + $value = Cache::get('key'); - Cache::put('key', 'value', $minutes); + $value = Cache::get('key', 'default'); -#### အချိန်ကန့်သတ်ဖို့အတွက် Carbon Objects အသုံးပြုခြင်း +You may even pass a `Closure` as the default value. The result of the `Closure` will be returned if the specified item does not exist in the cache. Passing a Closure allows you to defer the retrieval of default values from a database or other external service: - $expiresAt = Carbon::now()->addMinutes(10); + $value = Cache::get('key', function () { + return DB::table(...)->get(); + }); - Cache::put('key', 'value', $expiresAt); +#### Checking For Item Existence -#### အချက်အလက်သည် Cache ထဲတွင် ရှိမနေလျှင် ထပ်ထည့်ခြင်း +The `has` method may be used to determine if an item exists in the cache. This method will return `false` if the value is `null` or `false`: - Cache::add('key', 'value', $minutes); + if (Cache::has('key')) { + // + } -အကယ်၍ အချက်အလက်ဟာ cache ထဲမှာ **ရှိနေလျှင်** `add` method ဟာ `true` return ပြန်မှာဖြစ်ပြီး၊ အဲ့လိုမဟုတ်ရင်တော့ `false` return ပြန်မှာဖြစ်ပါတယ်။ +#### Incrementing / Decrementing Values -#### Cache ရှိမရှိ စစ်ဆေးခြင်း +The `increment` and `decrement` methods may be used to adjust the value of integer items in the cache. Both of these methods accept an optional second argument indicating the amount by which to increment or decrement the item's value: - if (Cache::has('key')) - { - // - } + Cache::increment('key'); + Cache::increment('key', $amount); + Cache::decrement('key'); + Cache::decrement('key', $amount); -#### Cache ထဲမှ အချက်အလက်ကို ရယူခြင်း +#### Retrieve & Store - $value = Cache::get('key'); +Sometimes you may wish to retrieve an item from the cache, but also store a default value if the requested item doesn't exist. For example, you may wish to retrieve all users from the cache or, if they don't exist, retrieve them from the database and add them to the cache. You may do this using the `Cache::remember` method: -#### အချက်အလက်ရယူခြင်း (သို့မဟုတ်) Default Value တစ်ခု return ပြန်ခြင်း + $value = Cache::remember('users', $minutes, function () { + return DB::table('users')->get(); + }); - $value = Cache::get('key', 'default'); +If the item does not exist in the cache, the `Closure` passed to the `remember` method will be executed and its result will be placed in the cache. - $value = Cache::get('key', function() { return 'default'; }); +#### Retrieve & Delete -#### အချက်အလက်ကို Cache ထဲသို့ အကန့်မသတ်မရှိသိမ်းဆည်းခြင်း +If you need to retrieve an item from the cache and then delete the item, you may use the `pull` method. Like the `get` method, `null` will be returned if the item does not exist in the cache: - Cache::forever('key', 'value'); + $value = Cache::pull('key'); -တစ်ခါတစ်ရံမှာ cache ထဲက အချက်အလက်ကိုလဲ ယူချင်တယ်၊ အကယ်၍ အဲ့ဒီအချက်အလက်ရှိမနေဘူးဆိုရင်လည်း cache ထဲကို default value တစ်ခု ထည့်ထားခဲ့ချင်တဲ့ အခြေအနေတွေရှိလာနိုင်ပါတယ်။ အဲ့ဒီလို အခြေအနေမျိုးအတွက် `Cache::remember` method ကိုအသုံးပြုနိုင်ပါတယ်။ + +### Storing Items In The Cache - $value = Cache::remember('users', $minutes, function() - { - return DB::table('users')->get(); - }); +You may use the `put` method on the `Cache` facade to store items in the cache. When you place an item in the cache, you need to specify the number of minutes for which the value should be cached: -`remember` နဲ့ `forever` method နှစ်ခုလုံးကို ပေါင်းစပ်ပြီး အသုံးပြုနိုင်ပါသေးတယ်။ + Cache::put('key', 'value', $minutes); - $value = Cache::rememberForever('users', function() - { - return DB::table('users')->get(); - }); +Instead of passing the number of minutes as an integer, you may also pass a `DateTime` instance representing the expiration time of the cached item: -Cache ထဲမှာသိမ်းဆည်းလိုက်တဲ့ အချက်အလက်တွေဟာ နံပါတ်စဉ်အလိုက်သိမ်းဆည်းတာဖြစ်တဲ့အတွက် သင့်အနေနဲ့ ဘယ်လို အချက်အလက်အမျိုးအစားကိုမဆို လွတ်လပ်စွာ သိမ်းဆည်းနိုင်ကြောင်း သတိပြုပါလေ။ + $expiresAt = Carbon::now()->addMinutes(10); -#### Cache ထဲရှိ အချက်အလက်ကို ဆွဲထုတ်ခြင်း + Cache::put('key', 'value', $expiresAt); -Cache ထဲမှ အချက်အလက်ကို ရယူအသုံးပြုပြီးတာနဲ့ ဖျက်ပြစ်လိုက်ချင်တယ်ဆိုရင်တော့၊ `pull` method ကိုအသုံးပြုနိုင်ပါတယ်။ +#### Store If Not Present - $value = Cache::pull('key'); +The `add` method will only add the item to the cache if it does not already exist in the cache store. The method will return `true` if the item is actually added to the cache. Otherwise, the method will return `false`: -#### Cache ထဲမှ အချက်အလက်ကို ပယ်ဖျက်ခြင်း + Cache::add('key', 'value', $minutes); - Cache::forget('key'); +#### Storing Items Forever - -## တန်ဖိုး ထပ်တိုးခြင်း နှင့် လျော့ချခြင်း +The `forever` method may be used to store an item in the cache permanently. Since these items will not expire, they must be manually removed from the cache using the `forget` method: -`file` နဲ့ `database` driver မှလွဲ၍ ကျန်တဲ့ cache drivers တွေအားလုံးကို `increment` နဲ့ `decrement`လုပ်ဆောင်ချက်တွေအတွက် အထောက်အပံ့ပေးထားပါတယ်။ + Cache::forever('key', 'value'); -#### အချက်အလက်တန်ဖိုး ထပ်တိုးခြင်း +> {tip} If you are using the Memcached driver, items that are stored "forever" may be removed when the cache reaches its size limit. - Cache::increment('key'); + +### Removing Items From The Cache - Cache::increment('key', $amount); +You may remove items from the cache using the `forget` method: -#### အချက်အလက်တန်ဖိုးလျော့ချခြင်း + Cache::forget('key'); - Cache::decrement('key'); +You may clear the entire cache using the `flush` method: - Cache::decrement('key', $amount); + Cache::flush(); + +> {note} Flushing the cache does not respect the cache prefix and will remove all entries from the cache. Consider this carefully when clearing a cache which is shared by other applications. + + +### The Cache Helper + +In addition to using the `Cache` facade or [cache contract](/docs/{{version}}/contracts), you may also use the global `cache` function to retrieve and store data via the cache. When the `cache` function is called with a single, string argument, it will return the value of the given key: + + $value = cache('key'); + +If you provide an array of key / value pairs and an expiration time to the function, it will store values in the cache for the specified duration: + + cache(['key' => 'value'], $minutes); + + cache(['key' => 'value'], Carbon::now()->addSeconds(10)); + +> {tip} When testing call to the global `cache` function, you may use the `Cache::shouldReceive` method just as if you were [testing a facade](/docs/{{version}}/mocking#mocking-facades). -## Cache များအား အုပ်စုဖွဲ့ခြင်း +## Cache Tags + +> {note} Cache tags are not supported when using the `file` or `database` cache drivers. Furthermore, when using multiple tags with caches that are stored "forever", performance will be best with a driver such as `memcached`, which automatically purges stale records. + + +### Storing Tagged Cache Items + +Cache tags allow you to tag related items in the cache and then flush all cached values that have been assigned a given tag. You may access a tagged cache by passing in an ordered array of tag names. For example, let's access a tagged cache and `put` value in the cache: + + Cache::tags(['people', 'artists'])->put('John', $john, $minutes); + + Cache::tags(['people', 'authors'])->put('Anne', $anne, $minutes); + + +### Accessing Tagged Cache Items + +To retrieve a tagged cache item, pass the same ordered list of tags to the `tags` method and then call the `get` method with the key you wish to retrieve: + + $john = Cache::tags(['people', 'artists'])->get('John'); + + $anne = Cache::tags(['people', 'authors'])->get('Anne'); + + +### Removing Tagged Cache Items + +You may flush all items that are assigned a tag or list of tags. For example, this statement would remove all caches tagged with either `people`, `authors`, or both. So, both `Anne` and `John` would be removed from the cache: + + Cache::tags(['people', 'authors'])->flush(); + +In contrast, this statement would remove only caches tagged with `authors`, so `Anne` would be removed, but not `John`: + + Cache::tags('authors')->flush(); + + +## Adding Custom Cache Drivers + + +### Writing The Driver + +To create our custom cache driver, we first need to implement the `Illuminate\Contracts\Cache\Store` [contract](/docs/{{version}}/contracts) contract. So, a MongoDB cache implementation would look something like this: + + **သတိပြုရန်:** `file` သို့မဟုတ် `database` cache driver သုံးထားရင်တော့ Cache tags ကို အထောက်အပံ့ပေးမှာမဟုတ်ပါဘူး။ ၎င်းအပြင် cache ကို tags တွေနဲ့တွဲသုံးမယ်ဆိုရင် အဲ့ဒီ cache ကို အမြဲတမ်းသိမ်းဆည်းထားမှာဖြစ်တဲ့အတွက် `memcached` ကဲသို့သော driver ကိုအသုံးပြုမှသာ permormance အတွက်ပိုပြီးအဆင်ပြေစေမှာပါ။ အဲ့ဒီတော့မှ အသုံးမလိုတော့တဲ့ အချက်အလက်တွေကို အလိုအလျှောက် ပယ်ဖျက်ပေးမှာဖြစ်ပါတယ်။ + use Illuminate\Contracts\Cache\Store; -#### Cache များအား အုပ်စုဖွဲ့ခြင်း + class MongoStore implements Store + { + public function get($key) {} + public function many(array $keys); + public function put($key, $value, $minutes) {} + public function putMany(array $values, $minutes); + public function increment($key, $value = 1) {} + public function decrement($key, $value = 1) {} + public function forever($key, $value) {} + public function forget($key) {} + public function flush() {} + public function getPrefix() {} + } -Cache ထဲမှာရှိတဲ့ ဆက်စပ်နေတဲ့ အချက်အလက်တွေကို အတူတကွအုပ်စုဖွဲ့ပေးခြင်းကို cache tags ကပြုလုပ်ပေးနိုင်ပါတယ်။ ပြီးရင်တော့ ပေးထားခဲ့တဲနာမည်အတိုင်းပြန်ပြီး လွယ်လွယ်ကူကူပဲ ပြန်လည်ပယ်ဖျက်နိုင်ပါတယ်။ Cache တွေကို တစ်ခုတစည်းထဲ အုပ်စုဖွဲ့ထားဖို့အတွက် `tags` method ကိုအသုံးပြုရပါမယ်။ +We just need to implement each of these methods using a MongoDB connection. For an example of how to implement each of these methods, take a look at the `Illuminate\Cache\MemcachedStore` in the framework source code. Once our implementation is complete, we can finish our custom driver registration. -Cache တွေကို တွဲစပ်ဖို့အတွက် `tags` method ထဲသို့ အမည်များကို `,` ခံ၍သော်လည်းကောင်း၊ array အနေနှင့် passing ပေး၍သော်လည်းကောင်း သိမ်းဆည်းနိုင်ပါတယ်။ + Cache::extend('mongo', function ($app) { + return Cache::repository(new MongoStore); + }); - Cache::tags('people', 'authors')->put('John', $john, $minutes); +> {tip} If you're wondering where to put your custom cache driver code, you could create an `Extensions` namespace within your `app` directory. However, keep in mind that Laravel does not have a rigid application structure and you are free to organize your application according to your preferences. - Cache::tags(array('people', 'artists'))->put('Anne', $anne, $minutes); + +### Registering The Driver -Cache တွေကိုတစ်ခုတစည်းထဲ အုပ်စုဖွဲ့ထားဖို့အတွက် နှစ်သက်ရာ caching method ကိုအသုံးပြုနိုင်ပါတယ်။ `remember`, `forever` နှင့် `rememberForever` စတာတွေအပါအဝင်ပေါ့။ `increment` နဲ့ `decrement` method တွေကိုတော့ အသုံးပြုလို့ရမှာမဟုတ်ပါဘူး။ +To register the custom cache driver with Laravel, we will use the `extend` method on the `Cache` facade. The call to `Cache::extend` could be done in the `boot` method of the default `App\Providers\AppServiceProvider` that ships with fresh Laravel applications, or you may create your own service provider to house the extension - just don't forget to register the provider in the `config/app.php` provider array: -#### အုပ်စုဖွဲ့ထားသော Cache ထဲမှ အချက်အလက်ကို ရယူခြင်း + get('Anne'); + use App\Extensions\MongoStore; + use Illuminate\Support\Facades\Cache; + use Illuminate\Support\ServiceProvider; - $john = Cache::tags(array('people', 'authors'))->get('John'); + class CacheServiceProvider extends ServiceProvider + { + /** + * Perform post-registration booting of services. + * + * @return void + */ + public function boot() + { + Cache::extend('mongo', function ($app) { + return Cache::repository(new MongoStore); + }); + } -ပြန်လည်ပယ်ဖျက်ချင်တယ်ဆိုလျင်လဲ အုပ်စုဖွဲ့ခြင်းပြုလုပ်စဉ်ကပေးထားခဲ့သော နာမည်တစ်ခု သို့မဟုတ် တစ်ခုထက်ပိုသော အမည်များကို အသုံးပြုပြီးပယ်ဖျက်နိုင်ပါတယ်။ အောက်မှာပေးထားတဲ့ ဥပမာကို ကြည့်မယ်ဆိုရင် `people` အုပ်စုကော `author` အုပ်စုကိုကော ပယ်ဖျက်လိုက်တာဖြစ်ပါတယ်။ အဲ့ဒီအတွက် အဲ့ဒီအုပ်စုနှစ်ခုထဲမှာပါတဲ့ "Anne" နဲ့ "John" ကို cache ထဲကနေ ဖျက်သွားမှာဖြစ်ပါတယ်။ + /** + * Register bindings in the container. + * + * @return void + */ + public function register() + { + // + } + } - Cache::tags('people', 'authors')->flush(); +The first argument passed to the `extend` method is the name of the driver. This will correspond to your `driver` option in the `config/cache.php` configuration file. The second argument is a Closure that should return an `Illuminate\Cache\Repository` instance. The Closure will be passed an `$app` instance, which is an instance of the [service container](/docs/{{version}}/container). -အောက်မှာပြထားတဲ့ ဥပမာအရဆိုရင် `authors` အုပ်စုကိုပဲပယ်ဖျက်လိုက်တာဖြစ်ပါတယ်။ အဲ့ဒါကြောင့် `authors` အုပ်စုထဲမှာပါတဲ့ "John" ကိုပဲဖျက်သွားမှာဖြစ်ပြီး "Anne" ကိုဖျက်သွားမှာမဟုတ်ပါဘူး။ အပေါ်ကဥပမာနဲ့ အောက်က ဥပမာကို ယှဉ်ကြည့်ပါ။ +Once your extension is registered, simply update your `config/cache.php` configuration file's `driver` option to the name of your extension. - Cache::tags('authors')->flush(); + +## Events - -## Database Cache +To execute code on every cache operation, you may listen for the [events](/docs/{{version}}/events) fired by the cache. Typically, you should place these event listeners within your `EventServiceProvider`: -`database` cache driver ကိုအသုံးပြုမယ်ဆိုရင်တော့ cache အချက်အလက်တွေကိုသိမ်းဆည်းဖို့အတွက် table တစ်ခုပြုလုပ်ပေးဖို့ လိုပါတယ်။ အောက်မှာ `Schema` နဲ့ cache table ပြုလုပ်ထားပုံကို ဥပမာအနေနဲ့ပြပေးထားပါတယ်။ + /** + * The event listener mappings for the application. + * + * @var array + */ + protected $listen = [ + 'Illuminate\Cache\Events\CacheHit' => [ + 'App\Listeners\LogCacheHit', + ], - Schema::create('cache', function($table) - { - $table->string('key')->unique(); - $table->text('value'); - $table->integer('expiration'); - }); \ No newline at end of file + 'Illuminate\Cache\Events\CacheMissed' => [ + 'App\Listeners\LogCacheMissed', + ], + + 'Illuminate\Cache\Events\KeyForgotten' => [ + 'App\Listeners\LogKeyForgotten', + ], + + 'Illuminate\Cache\Events\KeyWritten' => [ + 'App\Listeners\LogKeyWritten', + ], + ]; diff --git a/collections.md b/collections.md new file mode 100644 index 0000000..e71060b --- /dev/null +++ b/collections.md @@ -0,0 +1,1477 @@ +# Collections + +- [Introduction](#introduction) + - [Creating Collections](#creating-collections) +- [Available Methods](#available-methods) +- [Higher Order Messages](#higher-order-messages) + + +## Introduction + +The `Illuminate\Support\Collection` class provides a fluent, convenient wrapper for working with arrays of data. For example, check out the following code. We'll use the `collect` helper to create a new collection instance from the array, run the `strtoupper` function on each element, and then remove all empty elements: + + $collection = collect(['taylor', 'abigail', null])->map(function ($name) { + return strtoupper($name); + }) + ->reject(function ($name) { + return empty($name); + }); + + +As you can see, the `Collection` class allows you to chain its methods to perform fluent mapping and reducing of the underlying array. In general, collections are immutable, meaning every `Collection` method returns an entirely new `Collection` instance. + + +### Creating Collections + +As mentioned above, the `collect` helper returns a new `Illuminate\Support\Collection` instance for the given array. So, creating a collection is as simple as: + + $collection = collect([1, 2, 3]); + +> {tip} The results of [Eloquent](/docs/{{version}}/eloquent) queries are always returned as `Collection` instances. + + +## Available Methods + +For the remainder of this documentation, we'll discuss each method available on the `Collection` class. Remember, all of these methods may be chained to fluently manipulating the underlying array. Furthermore, almost every method returns a new `Collection` instance, allowing you to preserve the original copy of the collection when necessary: + + + +
    + +[all](#method-all) +[avg](#method-avg) +[chunk](#method-chunk) +[collapse](#method-collapse) +[combine](#method-combine) +[contains](#method-contains) +[count](#method-count) +[diff](#method-diff) +[diffKeys](#method-diffkeys) +[each](#method-each) +[every](#method-every) +[except](#method-except) +[filter](#method-filter) +[first](#method-first) +[flatMap](#method-flatmap) +[flatten](#method-flatten) +[flip](#method-flip) +[forget](#method-forget) +[forPage](#method-forpage) +[get](#method-get) +[groupBy](#method-groupby) +[has](#method-has) +[implode](#method-implode) +[intersect](#method-intersect) +[isEmpty](#method-isempty) +[keyBy](#method-keyby) +[keys](#method-keys) +[last](#method-last) +[map](#method-map) +[mapWithKeys](#method-mapwithkeys) +[max](#method-max) +[merge](#method-merge) +[min](#method-min) +[nth](#method-nth) +[only](#method-only) +[partition](#method-partition) +[pipe](#method-pipe) +[pluck](#method-pluck) +[pop](#method-pop) +[prepend](#method-prepend) +[pull](#method-pull) +[push](#method-push) +[put](#method-put) +[random](#method-random) +[reduce](#method-reduce) +[reject](#method-reject) +[reverse](#method-reverse) +[search](#method-search) +[shift](#method-shift) +[shuffle](#method-shuffle) +[slice](#method-slice) +[sort](#method-sort) +[sortBy](#method-sortby) +[sortByDesc](#method-sortbydesc) +[splice](#method-splice) +[split](#method-split) +[sum](#method-sum) +[take](#method-take) +[toArray](#method-toarray) +[toJson](#method-tojson) +[transform](#method-transform) +[union](#method-union) +[unique](#method-unique) +[values](#method-values) +[where](#method-where) +[whereStrict](#method-wherestrict) +[whereIn](#method-wherein) +[whereInStrict](#method-whereinstrict) +[zip](#method-zip) + +
    + + +## Method Listing + + + + +#### `all()` {#collection-method .first-collection-method} + +The `all` method returns the underlying array represented by the collection: + + collect([1, 2, 3])->all(); + + // [1, 2, 3] + + +#### `avg()` {#collection-method} + +The `avg` method returns the average of all items in the collection: + + collect([1, 2, 3, 4, 5])->avg(); + + // 3 + +If the collection contains nested arrays or objects, you should pass a key to use for determining which values to calculate the average: + + $collection = collect([ + ['name' => 'JavaScript: The Good Parts', 'pages' => 176], + ['name' => 'JavaScript: The Definitive Guide', 'pages' => 1096], + ]); + + $collection->avg('pages'); + + // 636 + + +#### `chunk()` {#collection-method} + +The `chunk` method breaks the collection into multiple, smaller collections of a given size: + + $collection = collect([1, 2, 3, 4, 5, 6, 7]); + + $chunks = $collection->chunk(4); + + $chunks->toArray(); + + // [[1, 2, 3, 4], [5, 6, 7]] + +This method is especially useful in [views](/docs/{{version}}/views) when working with a grid system such as [Bootstrap](https://getbootstrap.com/css/#grid). Imagine you have a collection of [Eloquent](/docs/{{version}}/eloquent) models you want to display in a grid: + + @foreach ($products->chunk(3) as $chunk) +
    + @foreach ($chunk as $product) +
    {{ $product->name }}
    + @endforeach +
    + @endforeach + + +#### `collapse()` {#collection-method} + +The `collapse` method collapses a collection of arrays into a single, flat collection: + + $collection = collect([[1, 2, 3], [4, 5, 6], [7, 8, 9]]); + + $collapsed = $collection->collapse(); + + $collapsed->all(); + + // [1, 2, 3, 4, 5, 6, 7, 8, 9] + + +#### `combine()` {#collection-method} + +The `combine` method combines the keys of the collection with the values of another array or collection: + + $collection = collect(['name', 'age']); + + $combined = $collection->combine(['George', 29]); + + $combined->all(); + + // ['name' => 'George', 'age' => 29] + + +#### `contains()` {#collection-method} + +The `contains` method determines whether the collection contains a given item: + + $collection = collect(['name' => 'Desk', 'price' => 100]); + + $collection->contains('Desk'); + + // true + + $collection->contains('New York'); + + // false + +You may also pass a key / value pair to the `contains` method, which will determine if the given pair exists in the collection: + + $collection = collect([ + ['product' => 'Desk', 'price' => 200], + ['product' => 'Chair', 'price' => 100], + ]); + + $collection->contains('product', 'Bookcase'); + + // false + +Finally, you may also pass a callback to the `contains` method to perform your own truth test: + + $collection = collect([1, 2, 3, 4, 5]); + + $collection->contains(function ($value, $key) { + return $value > 5; + }); + + // false + + +#### `count()` {#collection-method} + +The `count` method returns the total number of items in the collection: + + $collection = collect([1, 2, 3, 4]); + + $collection->count(); + + // 4 + + +#### `diff()` {#collection-method} + +The `diff` method compares the collection against another collection or a plain PHP `array` based on its values. This method will return the values in the original collection that are not present in the given collection: + + $collection = collect([1, 2, 3, 4, 5]); + + $diff = $collection->diff([2, 4, 6, 8]); + + $diff->all(); + + // [1, 3, 5] + + +#### `diffKeys()` {#collection-method} + +The `diffKeys` method compares the collection against another collection or a plain PHP `array` based on its keys. This method will return the key / value pairs in the original collection that are not present in the given collection: + + $collection = collect([ + 'one' => 10, + 'two' => 20, + 'three' => 30, + 'four' => 40, + 'five' => 50, + ]); + + $diff = $collection->diffKeys([ + 'two' => 2, + 'four' => 4, + 'six' => 6, + 'eight' => 8, + ]); + + $diff->all(); + + // ['one' => 10, 'three' => 30, 'five' => 50] + + +#### `each()` {#collection-method} + +The `each` method iterates over the items in the collection and passes each item to a callback: + + $collection = $collection->each(function ($item, $key) { + // + }); + +If you would like to stop iterating through the items, you may return `false` from your callback: + + $collection = $collection->each(function ($item, $key) { + if (/* some condition */) { + return false; + } + }); + + +#### `every()` {#collection-method} + +The `every` method may be used to verify that all elements of a collection pass a given truth test: + + collect([1, 2, 3, 4])->every(function ($value, $key) { + return $value > 2; + }); + + // false + + +#### `except()` {#collection-method} + +The `except` method returns all items in the collection except for those with the specified keys: + + $collection = collect(['product_id' => 1, 'price' => 100, 'discount' => false]); + + $filtered = $collection->except(['price', 'discount']); + + $filtered->all(); + + // ['product_id' => 1] + +For the inverse of `except`, see the [only](#method-only) method. + + +#### `filter()` {#collection-method} + +The `filter` method filters the collection using the given callback, keeping only those items that pass a given truth test: + + $collection = collect([1, 2, 3, 4]); + + $filtered = $collection->filter(function ($value, $key) { + return $value > 2; + }); + + $filtered->all(); + + // [3, 4] + +If no callback is supplied, all entries of the collection that are equivalent to `false` will be removed: + + $collection = collect([1, 2, 3, null, false, '', 0, []]); + + $collection->filter()->all(); + + // [1, 2, 3] + +For the inverse of `filter`, see the [reject](#method-reject) method. + + +#### `first()` {#collection-method} + +The `first` method returns the first element in the collection that passes a given truth test: + + collect([1, 2, 3, 4])->first(function ($value, $key) { + return $value > 2; + }); + + // 3 + +You may also call the `first` method with no arguments to get the first element in the collection. If the collection is empty, `null` is returned: + + collect([1, 2, 3, 4])->first(); + + // 1 + + +#### `flatMap()` {#collection-method} + +The `flatMap` method iterates through the collection and passes each value to the given callback. The callback is free to modify the item and return it, thus forming a new collection of modified items. Then, the array is flattened by a level: + + $collection = collect([ + ['name' => 'Sally'], + ['school' => 'Arkansas'], + ['age' => 28] + ]); + + $flattened = $collection->flatMap(function ($values) { + return array_map('strtoupper', $values); + }); + + $flattened->all(); + + // ['name' => 'SALLY', 'school' => 'ARKANSAS', 'age' => '28']; + + +#### `flatten()` {#collection-method} + +The `flatten` method flattens a multi-dimensional collection into a single dimension: + + $collection = collect(['name' => 'taylor', 'languages' => ['php', 'javascript']]); + + $flattened = $collection->flatten(); + + $flattened->all(); + + // ['taylor', 'php', 'javascript']; + +You may optionally pass the function a "depth" argument: + + $collection = collect([ + 'Apple' => [ + ['name' => 'iPhone 6S', 'brand' => 'Apple'], + ], + 'Samsung' => [ + ['name' => 'Galaxy S7', 'brand' => 'Samsung'] + ], + ]); + + $products = $collection->flatten(1); + + $products->values()->all(); + + /* + [ + ['name' => 'iPhone 6S', 'brand' => 'Apple'], + ['name' => 'Galaxy S7', 'brand' => 'Samsung'], + ] + */ + +In this example, calling `flatten` without providing the depth would have also flattened the nested arrays, resulting in `['iPhone 6S', 'Apple', 'Galaxy S7', 'Samsung']`. Providing a depth allows you to restrict the levels of nested arrays that will be flattened. + + +#### `flip()` {#collection-method} + +The `flip` method swaps the collection's keys with their corresponding values: + + $collection = collect(['name' => 'taylor', 'framework' => 'laravel']); + + $flipped = $collection->flip(); + + $flipped->all(); + + // ['taylor' => 'name', 'laravel' => 'framework'] + + +#### `forget()` {#collection-method} + +The `forget` method removes an item from the collection by its key: + + $collection = collect(['name' => 'taylor', 'framework' => 'laravel']); + + $collection->forget('name'); + + $collection->all(); + + // ['framework' => 'laravel'] + +> {note} Unlike most other collection methods, `forget` does not return a new modified collection; it modifies the collection it is called on. + + +#### `forPage()` {#collection-method} + +The `forPage` method returns a new collection containing the items that would be present on a given page number. The method accepts the page number as its first argument and the number of items to show per page as its second argument: + + $collection = collect([1, 2, 3, 4, 5, 6, 7, 8, 9]); + + $chunk = $collection->forPage(2, 3); + + $chunk->all(); + + // [4, 5, 6] + + +#### `get()` {#collection-method} + +The `get` method returns the item at a given key. If the key does not exist, `null` is returned: + + $collection = collect(['name' => 'taylor', 'framework' => 'laravel']); + + $value = $collection->get('name'); + + // taylor + +You may optionally pass a default value as the second argument: + + $collection = collect(['name' => 'taylor', 'framework' => 'laravel']); + + $value = $collection->get('foo', 'default-value'); + + // default-value + +You may even pass a callback as the default value. The result of the callback will be returned if the specified key does not exist: + + $collection->get('email', function () { + return 'default-value'; + }); + + // default-value + + +#### `groupBy()` {#collection-method} + +The `groupBy` method groups the collection's items by a given key: + + $collection = collect([ + ['account_id' => 'account-x10', 'product' => 'Chair'], + ['account_id' => 'account-x10', 'product' => 'Bookcase'], + ['account_id' => 'account-x11', 'product' => 'Desk'], + ]); + + $grouped = $collection->groupBy('account_id'); + + $grouped->toArray(); + + /* + [ + 'account-x10' => [ + ['account_id' => 'account-x10', 'product' => 'Chair'], + ['account_id' => 'account-x10', 'product' => 'Bookcase'], + ], + 'account-x11' => [ + ['account_id' => 'account-x11', 'product' => 'Desk'], + ], + ] + */ + +In addition to passing a string `key`, you may also pass a callback. The callback should return the value you wish to key the group by: + + $grouped = $collection->groupBy(function ($item, $key) { + return substr($item['account_id'], -3); + }); + + $grouped->toArray(); + + /* + [ + 'x10' => [ + ['account_id' => 'account-x10', 'product' => 'Chair'], + ['account_id' => 'account-x10', 'product' => 'Bookcase'], + ], + 'x11' => [ + ['account_id' => 'account-x11', 'product' => 'Desk'], + ], + ] + */ + + +#### `has()` {#collection-method} + +The `has` method determines if a given key exists in the collection: + + $collection = collect(['account_id' => 1, 'product' => 'Desk']); + + $collection->has('product'); + + // true + + +#### `implode()` {#collection-method} + +The `implode` method joins the items in a collection. Its arguments depend on the type of items in the collection. If the collection contains arrays or objects, you should pass the key of the attributes you wish to join, and the "glue" string you wish to place between the values: + + $collection = collect([ + ['account_id' => 1, 'product' => 'Desk'], + ['account_id' => 2, 'product' => 'Chair'], + ]); + + $collection->implode('product', ', '); + + // Desk, Chair + +If the collection contains simple strings or numeric values, simply pass the "glue" as the only argument to the method: + + collect([1, 2, 3, 4, 5])->implode('-'); + + // '1-2-3-4-5' + + +#### `intersect()` {#collection-method} + +The `intersect` method removes any values from the original collection that are not present in the given `array` or collection. The resulting collection will preserve the original collection's keys: + + $collection = collect(['Desk', 'Sofa', 'Chair']); + + $intersect = $collection->intersect(['Desk', 'Chair', 'Bookcase']); + + $intersect->all(); + + // [0 => 'Desk', 2 => 'Chair'] + + +#### `isEmpty()` {#collection-method} + +The `isEmpty` method returns `true` if the collection is empty; otherwise, `false` is returned: + + collect([])->isEmpty(); + + // true + + +#### `keyBy()` {#collection-method} + +The `keyBy` method keys the collection by the given key. If multiple items have the same key, only the last one will appear in the new collection: + + $collection = collect([ + ['product_id' => 'prod-100', 'name' => 'desk'], + ['product_id' => 'prod-200', 'name' => 'chair'], + ]); + + $keyed = $collection->keyBy('product_id'); + + $keyed->all(); + + /* + [ + 'prod-100' => ['product_id' => 'prod-100', 'name' => 'Desk'], + 'prod-200' => ['product_id' => 'prod-200', 'name' => 'Chair'], + ] + */ + +You may also pass a callback to the method. The callback should return the value to key the collection by: + + $keyed = $collection->keyBy(function ($item) { + return strtoupper($item['product_id']); + }); + + $keyed->all(); + + /* + [ + 'PROD-100' => ['product_id' => 'prod-100', 'name' => 'Desk'], + 'PROD-200' => ['product_id' => 'prod-200', 'name' => 'Chair'], + ] + */ + + + +#### `keys()` {#collection-method} + +The `keys` method returns all of the collection's keys: + + $collection = collect([ + 'prod-100' => ['product_id' => 'prod-100', 'name' => 'Desk'], + 'prod-200' => ['product_id' => 'prod-200', 'name' => 'Chair'], + ]); + + $keys = $collection->keys(); + + $keys->all(); + + // ['prod-100', 'prod-200'] + + +#### `last()` {#collection-method} + +The `last` method returns the last element in the collection that passes a given truth test: + + collect([1, 2, 3, 4])->last(function ($value, $key) { + return $value < 3; + }); + + // 2 + +You may also call the `last` method with no arguments to get the last element in the collection. If the collection is empty, `null` is returned: + + collect([1, 2, 3, 4])->last(); + + // 4 + + +#### `map()` {#collection-method} + +The `map` method iterates through the collection and passes each value to the given callback. The callback is free to modify the item and return it, thus forming a new collection of modified items: + + $collection = collect([1, 2, 3, 4, 5]); + + $multiplied = $collection->map(function ($item, $key) { + return $item * 2; + }); + + $multiplied->all(); + + // [2, 4, 6, 8, 10] + +> {note} Like most other collection methods, `map` returns a new collection instance; it does not modify the collection it is called on. If you want to transform the original collection, use the [`transform`](#method-transform) method. + + +#### `mapWithKeys()` {#collection-method} + +The `mapWithKeys` method iterates through the collection and passes each value to the given callback. The callback should return an associative array containing a single key / value pair: + + $collection = collect([ + [ + 'name' => 'John', + 'department' => 'Sales', + 'email' => 'john@example.com' + ], + [ + 'name' => 'Jane', + 'department' => 'Marketing', + 'email' => 'jane@example.com' + ] + ]); + + $keyed = $collection->mapWithKeys(function ($item) { + return [$item['email'] => $item['name']]; + }); + + $keyed->all(); + + /* + [ + 'john@example.com' => 'John', + 'jane@example.com' => 'Jane', + ] + */ + + +#### `max()` {#collection-method} + +The `max` method returns the maximum value of a given key: + + $max = collect([['foo' => 10], ['foo' => 20]])->max('foo'); + + // 20 + + $max = collect([1, 2, 3, 4, 5])->max(); + + // 5 + + +#### `merge()` {#collection-method} + +The `merge` method merges the given array with the original collection. If a string key in the given array matches a string key in the original collection, the given array's value will overwrite the value in the original collection: + + $collection = collect(['product_id' => 1, 'price' => 100]); + + $merged = $collection->merge(['price' => 200, 'discount' => false]); + + $merged->all(); + + // ['product_id' => 1, 'price' => 200, 'discount' => false] + +If the given array's keys are numeric, the values will be appended to the end of the collection: + + $collection = collect(['Desk', 'Chair']); + + $merged = $collection->merge(['Bookcase', 'Door']); + + $merged->all(); + + // ['Desk', 'Chair', 'Bookcase', 'Door'] + + +#### `min()` {#collection-method} + +The `min` method returns the minimum value of a given key: + + $min = collect([['foo' => 10], ['foo' => 20]])->min('foo'); + + // 10 + + $min = collect([1, 2, 3, 4, 5])->min(); + + // 1 + + +#### `nth()` {#collection-method} + +The `nth` method creates a new collection consisting of every n-th element: + + $collection = collect(['a', 'b', 'c', 'd', 'e', 'f']); + + $collection->nth(4); + + // ['a', 'e'] + +You may optionally pass an offset as the second argument: + + $collection->nth(4, 1); + + // ['b', 'f'] + + +#### `only()` {#collection-method} + +The `only` method returns the items in the collection with the specified keys: + + $collection = collect(['product_id' => 1, 'name' => 'Desk', 'price' => 100, 'discount' => false]); + + $filtered = $collection->only(['product_id', 'name']); + + $filtered->all(); + + // ['product_id' => 1, 'name' => 'Desk'] + +For the inverse of `only`, see the [except](#method-except) method. + + +#### `partition()` {#collection-method} + +The `partition` method may be combined with the `list` PHP function to separate elements that pass a given truth test from those that do not: + + $collection = collect([1, 2, 3, 4, 5, 6]); + + list($underThree, $aboveThree) = $collection->partition(function ($i) { + return $i < 3; + }); + + +#### `pipe()` {#collection-method} + +The `pipe` method passes the collection to the given callback and returns the result: + + $collection = collect([1, 2, 3]); + + $piped = $collection->pipe(function ($collection) { + return $collection->sum(); + }); + + // 6 + + +#### `pluck()` {#collection-method} + +The `pluck` method retrieves all of the values for a given key: + + $collection = collect([ + ['product_id' => 'prod-100', 'name' => 'Desk'], + ['product_id' => 'prod-200', 'name' => 'Chair'], + ]); + + $plucked = $collection->pluck('name'); + + $plucked->all(); + + // ['Desk', 'Chair'] + +You may also specify how you wish the resulting collection to be keyed: + + $plucked = $collection->pluck('name', 'product_id'); + + $plucked->all(); + + // ['prod-100' => 'Desk', 'prod-200' => 'Chair'] + + +#### `pop()` {#collection-method} + +The `pop` method removes and returns the last item from the collection: + + $collection = collect([1, 2, 3, 4, 5]); + + $collection->pop(); + + // 5 + + $collection->all(); + + // [1, 2, 3, 4] + + +#### `prepend()` {#collection-method} + +The `prepend` method adds an item to the beginning of the collection: + + $collection = collect([1, 2, 3, 4, 5]); + + $collection->prepend(0); + + $collection->all(); + + // [0, 1, 2, 3, 4, 5] + +You may also pass a second argument to set the key of the prepended item: + + $collection = collect(['one' => 1, 'two', => 2]); + + $collection->prepend(0, 'zero'); + + $collection->all(); + + // ['zero' => 0, 'one' => 1, 'two', => 2] + + +#### `pull()` {#collection-method} + +The `pull` method removes and returns an item from the collection by its key: + + $collection = collect(['product_id' => 'prod-100', 'name' => 'Desk']); + + $collection->pull('name'); + + // 'Desk' + + $collection->all(); + + // ['product_id' => 'prod-100'] + + +#### `push()` {#collection-method} + +The `push` method appends an item to the end of the collection: + + $collection = collect([1, 2, 3, 4]); + + $collection->push(5); + + $collection->all(); + + // [1, 2, 3, 4, 5] + + +#### `put()` {#collection-method} + +The `put` method sets the given key and value in the collection: + + $collection = collect(['product_id' => 1, 'name' => 'Desk']); + + $collection->put('price', 100); + + $collection->all(); + + // ['product_id' => 1, 'name' => 'Desk', 'price' => 100] + + +#### `random()` {#collection-method} + +The `random` method returns a random item from the collection: + + $collection = collect([1, 2, 3, 4, 5]); + + $collection->random(); + + // 4 - (retrieved randomly) + +You may optionally pass an integer to `random` to specify how many items you would like to randomly retrieve. A collection of items is always returned when explicitly passing the number of items you wish to receive: + + $random = $collection->random(3); + + $random->all(); + + // [2, 4, 5] - (retrieved randomly) + + +#### `reduce()` {#collection-method} + +The `reduce` method reduces the collection to a single value, passing the result of each iteration into the subsequent iteration: + + $collection = collect([1, 2, 3]); + + $total = $collection->reduce(function ($carry, $item) { + return $carry + $item; + }); + + // 6 + +The value for `$carry` on the first iteration is `null`; however, you may specify its initial value by passing a second argument to `reduce`: + + $collection->reduce(function ($carry, $item) { + return $carry + $item; + }, 4); + + // 10 + + +#### `reject()` {#collection-method} + +The `reject` method filters the collection using the given callback. The callback should return `true` if the item should be removed from the resulting collection: + + $collection = collect([1, 2, 3, 4]); + + $filtered = $collection->reject(function ($value, $key) { + return $value > 2; + }); + + $filtered->all(); + + // [1, 2] + +For the inverse of the `reject` method, see the [`filter`](#method-filter) method. + + +#### `reverse()` {#collection-method} + +The `reverse` method reverses the order of the collection's items: + + $collection = collect([1, 2, 3, 4, 5]); + + $reversed = $collection->reverse(); + + $reversed->all(); + + // [5, 4, 3, 2, 1] + + +#### `search()` {#collection-method} + +The `search` method searches the collection for the given value and returns its key if found. If the item is not found, `false` is returned. + + $collection = collect([2, 4, 6, 8]); + + $collection->search(4); + + // 1 + +The search is done using a "loose" comparison, meaning a string with an integer value will be considered equal to an integer of the same value. To use strict comparison, pass `true` as the second argument to the method: + + $collection->search('4', true); + + // false + +Alternatively, you may pass in your own callback to search for the first item that passes your truth test: + + $collection->search(function ($item, $key) { + return $item > 5; + }); + + // 2 + + +#### `shift()` {#collection-method} + +The `shift` method removes and returns the first item from the collection: + + $collection = collect([1, 2, 3, 4, 5]); + + $collection->shift(); + + // 1 + + $collection->all(); + + // [2, 3, 4, 5] + + +#### `shuffle()` {#collection-method} + +The `shuffle` method randomly shuffles the items in the collection: + + $collection = collect([1, 2, 3, 4, 5]); + + $shuffled = $collection->shuffle(); + + $shuffled->all(); + + // [3, 2, 5, 1, 4] // (generated randomly) + + +#### `slice()` {#collection-method} + +The `slice` method returns a slice of the collection starting at the given index: + + $collection = collect([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + + $slice = $collection->slice(4); + + $slice->all(); + + // [5, 6, 7, 8, 9, 10] + +If you would like to limit the size of the returned slice, pass the desired size as the second argument to the method: + + $slice = $collection->slice(4, 2); + + $slice->all(); + + // [5, 6] + +The returned slice will preserve keys by default. If you do not wish to preserve the original keys, you can use the `values` method to reindex them. + + +#### `sort()` {#collection-method} + +The `sort` method sorts the collection. The sorted collection keeps the original array keys, so in this example we'll use the [`values`](#method-values) method to reset the keys to consecutively numbered indexes: + + $collection = collect([5, 3, 1, 2, 4]); + + $sorted = $collection->sort(); + + $sorted->values()->all(); + + // [1, 2, 3, 4, 5] + +If your sorting needs are more advanced, you may pass a callback to `sort` with your own algorithm. Refer to the PHP documentation on [`usort`](https://secure.php.net/manual/en/function.usort.php#refsect1-function.usort-parameters), which is what the collection's `sort` method calls under the hood. + +> {tip} If you need to sort a collection of nested arrays or objects, see the [`sortBy`](#method-sortby) and [`sortByDesc`](#method-sortbydesc) methods. + + +#### `sortBy()` {#collection-method} + +The `sortBy` method sorts the collection by the given key. The sorted collection keeps the original array keys, so in this example we'll use the [`values`](#method-values) method to reset the keys to consecutively numbered indexes: + + $collection = collect([ + ['name' => 'Desk', 'price' => 200], + ['name' => 'Chair', 'price' => 100], + ['name' => 'Bookcase', 'price' => 150], + ]); + + $sorted = $collection->sortBy('price'); + + $sorted->values()->all(); + + /* + [ + ['name' => 'Chair', 'price' => 100], + ['name' => 'Bookcase', 'price' => 150], + ['name' => 'Desk', 'price' => 200], + ] + */ + +You can also pass your own callback to determine how to sort the collection values: + + $collection = collect([ + ['name' => 'Desk', 'colors' => ['Black', 'Mahogany']], + ['name' => 'Chair', 'colors' => ['Black']], + ['name' => 'Bookcase', 'colors' => ['Red', 'Beige', 'Brown']], + ]); + + $sorted = $collection->sortBy(function ($product, $key) { + return count($product['colors']); + }); + + $sorted->values()->all(); + + /* + [ + ['name' => 'Chair', 'colors' => ['Black']], + ['name' => 'Desk', 'colors' => ['Black', 'Mahogany']], + ['name' => 'Bookcase', 'colors' => ['Red', 'Beige', 'Brown']], + ] + */ + + +#### `sortByDesc()` {#collection-method} + +This method has the same signature as the [`sortBy`](#method-sortby) method, but will sort the collection in the opposite order. + + +#### `splice()` {#collection-method} + +The `splice` method removes and returns a slice of items starting at the specified index: + + $collection = collect([1, 2, 3, 4, 5]); + + $chunk = $collection->splice(2); + + $chunk->all(); + + // [3, 4, 5] + + $collection->all(); + + // [1, 2] + +You may pass a second argument to limit the size of the resulting chunk: + + $collection = collect([1, 2, 3, 4, 5]); + + $chunk = $collection->splice(2, 1); + + $chunk->all(); + + // [3] + + $collection->all(); + + // [1, 2, 4, 5] + +In addition, you can pass a third argument containing the new items to replace the items removed from the collection: + + $collection = collect([1, 2, 3, 4, 5]); + + $chunk = $collection->splice(2, 1, [10, 11]); + + $chunk->all(); + + // [3] + + $collection->all(); + + // [1, 2, 10, 11, 4, 5] + + +#### `split()` {#collection-method} + +The `split` method breaks a collection into the given number of groups: + + $collection = collect([1, 2, 3, 4, 5]); + + $groups = $collection->split(3); + + $groups->toArray(); + + // [[1, 2], [3, 4], [5]] + + +#### `sum()` {#collection-method} + +The `sum` method returns the sum of all items in the collection: + + collect([1, 2, 3, 4, 5])->sum(); + + // 15 + +If the collection contains nested arrays or objects, you should pass a key to use for determining which values to sum: + + $collection = collect([ + ['name' => 'JavaScript: The Good Parts', 'pages' => 176], + ['name' => 'JavaScript: The Definitive Guide', 'pages' => 1096], + ]); + + $collection->sum('pages'); + + // 1272 + +In addition, you may pass your own callback to determine which values of the collection to sum: + + $collection = collect([ + ['name' => 'Chair', 'colors' => ['Black']], + ['name' => 'Desk', 'colors' => ['Black', 'Mahogany']], + ['name' => 'Bookcase', 'colors' => ['Red', 'Beige', 'Brown']], + ]); + + $collection->sum(function ($product) { + return count($product['colors']); + }); + + // 6 + + +#### `take()` {#collection-method} + +The `take` method returns a new collection with the specified number of items: + + $collection = collect([0, 1, 2, 3, 4, 5]); + + $chunk = $collection->take(3); + + $chunk->all(); + + // [0, 1, 2] + +You may also pass a negative integer to take the specified amount of items from the end of the collection: + + $collection = collect([0, 1, 2, 3, 4, 5]); + + $chunk = $collection->take(-2); + + $chunk->all(); + + // [4, 5] + + +#### `toArray()` {#collection-method} + +The `toArray` method converts the collection into a plain PHP `array`. If the collection's values are [Eloquent](/docs/{{version}}/eloquent) models, the models will also be converted to arrays: + + $collection = collect(['name' => 'Desk', 'price' => 200]); + + $collection->toArray(); + + /* + [ + ['name' => 'Desk', 'price' => 200], + ] + */ + +> {note} `toArray` also converts all of the collection's nested objects to an array. If you want to get the raw underlying array, use the [`all`](#method-all) method instead. + + +#### `toJson()` {#collection-method} + +The `toJson` method converts the collection into JSON: + + $collection = collect(['name' => 'Desk', 'price' => 200]); + + $collection->toJson(); + + // '{"name":"Desk", "price":200}' + + +#### `transform()` {#collection-method} + +The `transform` method iterates over the collection and calls the given callback with each item in the collection. The items in the collection will be replaced by the values returned by the callback: + + $collection = collect([1, 2, 3, 4, 5]); + + $collection->transform(function ($item, $key) { + return $item * 2; + }); + + $collection->all(); + + // [2, 4, 6, 8, 10] + +> {note} Unlike most other collection methods, `transform` modifies the collection itself. If you wish to create a new collection instead, use the [`map`](#method-map) method. + + +#### `union()` {#collection-method} + +The `union` method adds the given array to the collection. If the given array contains keys that are already in the original collection, the original collection's values will be preferred: + + $collection = collect([1 => ['a'], 2 => ['b']]); + + $union = $collection->union([3 => ['c'], 1 => ['b']]); + + $union->all(); + + // [1 => ['a'], 2 => ['b'], 3 => ['c']] + + +#### `unique()` {#collection-method} + +The `unique` method returns all of the unique items in the collection. The returned collection keeps the original array keys, so in this example we'll use the [`values`](#method-values) method to reset the keys to consecutively numbered indexes: + + $collection = collect([1, 1, 2, 2, 3, 4, 2]); + + $unique = $collection->unique(); + + $unique->values()->all(); + + // [1, 2, 3, 4] + +When dealing with nested arrays or objects, you may specify the key used to determine uniqueness: + + $collection = collect([ + ['name' => 'iPhone 6', 'brand' => 'Apple', 'type' => 'phone'], + ['name' => 'iPhone 5', 'brand' => 'Apple', 'type' => 'phone'], + ['name' => 'Apple Watch', 'brand' => 'Apple', 'type' => 'watch'], + ['name' => 'Galaxy S6', 'brand' => 'Samsung', 'type' => 'phone'], + ['name' => 'Galaxy Gear', 'brand' => 'Samsung', 'type' => 'watch'], + ]); + + $unique = $collection->unique('brand'); + + $unique->values()->all(); + + /* + [ + ['name' => 'iPhone 6', 'brand' => 'Apple', 'type' => 'phone'], + ['name' => 'Galaxy S6', 'brand' => 'Samsung', 'type' => 'phone'], + ] + */ + +You may also pass your own callback to determine item uniqueness: + + $unique = $collection->unique(function ($item) { + return $item['brand'].$item['type']; + }); + + $unique->values()->all(); + + /* + [ + ['name' => 'iPhone 6', 'brand' => 'Apple', 'type' => 'phone'], + ['name' => 'Apple Watch', 'brand' => 'Apple', 'type' => 'watch'], + ['name' => 'Galaxy S6', 'brand' => 'Samsung', 'type' => 'phone'], + ['name' => 'Galaxy Gear', 'brand' => 'Samsung', 'type' => 'watch'], + ] + */ + + +#### `values()` {#collection-method} + +The `values` method returns a new collection with the keys reset to consecutive integers: + + $collection = collect([ + 10 => ['product' => 'Desk', 'price' => 200], + 11 => ['product' => 'Desk', 'price' => 200] + ]); + + $values = $collection->values(); + + $values->all(); + + /* + [ + 0 => ['product' => 'Desk', 'price' => 200], + 1 => ['product' => 'Desk', 'price' => 200], + ] + */ + +#### `where()` {#collection-method} + +The `where` method filters the collection by a given key / value pair: + + $collection = collect([ + ['product' => 'Desk', 'price' => 200], + ['product' => 'Chair', 'price' => 100], + ['product' => 'Bookcase', 'price' => 150], + ['product' => 'Door', 'price' => 100], + ]); + + $filtered = $collection->where('price', 100); + + $filtered->all(); + + /* + [ + ['product' => 'Chair', 'price' => 100], + ['product' => 'Door', 'price' => 100], + ] + */ + +The `where` method uses loose comparisons when checking item values. Use the [`whereStrict`](#method-wherestrict) method to filter using "strict" comparisons. + + +#### `whereStrict()` {#collection-method} + +This method has the same signature as the [`where`](#method-where) method; however, all values are compared using "strict" comparisons. + + +#### `whereIn()` {#collection-method} + +The `whereIn` method filters the collection by a given key / value contained within the given array. + + $collection = collect([ + ['product' => 'Desk', 'price' => 200], + ['product' => 'Chair', 'price' => 100], + ['product' => 'Bookcase', 'price' => 150], + ['product' => 'Door', 'price' => 100], + ]); + + $filtered = $collection->whereIn('price', [150, 200]); + + $filtered->all(); + + /* + [ + ['product' => 'Bookcase', 'price' => 150], + ['product' => 'Desk', 'price' => 200], + ] + */ + +The `whereIn` method uses "loose" comparisons when checking item values. Use the [`whereInStrict`](#method-whereinstrict) method to filter using strict comparisons. + + +#### `whereInStrict()` {#collection-method} + +This method has the same signature as the [`whereIn`](#method-wherein) method; however, all values are compared using strict comparisons. + + +#### `zip()` {#collection-method} + +The `zip` method merges together the values of the given array with the values of the original collection at the corresponding index: + + $collection = collect(['Chair', 'Desk']); + + $zipped = $collection->zip([100, 200]); + + $zipped->all(); + + // [['Chair', 100], ['Desk', 200]] + + +## Higher Order Messages + +Collections also provide support for "higher order messages", which are short-cuts for performing common actions on collections. The collection methods that provide higher order messages are: `contains`, `each`, `every`, `filter`, `first`, `map`, `partition`, `reject`, `sortBy`, `sortByDesc`, and `sum`. + +Each higher order message can be accessed as a dynamic property on a collection instance. For instance, let's use the `each` higher order message to call a method on each object within a collection: + + $users = User::where('votes', '>', 500)->get(); + + $users->each->markAsVip(); + +Likewise, we can use the `sum` higher order message to gather the total number of "votes" for a collection of users: + + $users = User::where('group', 'Development')->get(); + + return $users->sum->votes; diff --git a/commands.md b/commands.md deleted file mode 100644 index 80f6b86..0000000 --- a/commands.md +++ /dev/null @@ -1,142 +0,0 @@ -# Artisan Development - -- [Introduction](#introduction) -- [Building A Command](#building-a-command) -- [Registering Commands](#registering-commands) -- [Calling Other Commands](#calling-other-commands) - - -## Introduction - -သင့် application အတွက် ကိုယ်ပိုင် commands တွေကို Artisan နဲ့ ထပ်ပြီးပေါင်းထည့်နိုင်ဖို့စီစဉ်ထားပါတယ်။ သင့်ရဲ့ ကိုယ်ပိုင် command တွေကို `app/commands` မှာထက်ထည့်နိုင်ပါတယ်၊ သို့သော်လည်းသင့်ရဲ့ကိုယ်ပိုင် command တွေကို သင်ကြိုက်တဲ့ storage location မှာ ထည့်နိုင်ပါတယ် သင့်ရဲ့ commands တွေကို သင့်ရဲ့ `composer.json` settings မှာအခြေခံပြီး autoload လုပ်နိုင်ပါတယ်။ - - -## Building A Command - -### Generating The Class - -command တစ်ခုအသစ် create လုပ်ရန်အတွက် - သင့်အနေနဲ့ `command:make` Artisan command ကိုသုံးနိုင်ပါတယ်၊ အဲ့ဒါကသင်စတင်ဖို့ command stub တစ်ခုကို generate ထုတ်ပေးပါလိမ့်မယ်: - -#### Generate A New Command Class - - php artisan command:make FooCommand - -Default အရ generate လုပ်လိုက်တဲ့ commands တွေက `app/commands` မှာ သိမ်းဆည်းထားမှာပါ... သို့သော်လည်း သင့်ကိုယ်ပိုင် path ဒါမှမဟုတ် namespace တစ်ခု သတ်မှတ်ထားလို့လည်းရပါတယ်: - - php artisan command:make FooCommand --path=app/classes --namespace=Classes - -command create လုပ်တဲ့အချိန်မှာ `--command` option ကို terminal command name အဖြစ် assign လုပ်ရန်အသုံးပြုပါလိမ့်မယ်: - - php artisan command:make AssignUsers --command=users:assign - -### Writing The Command - -သင့်ရဲ့ command generate လုပ်ပြီးသွားတဲ့အချိန်မှာ သင့်အနေနဲ့ `name` နဲ့ `description` တွေရဲ့ class properties တွေကို ဖြည့်စွတ်သင့်ပါတယ်၊ အဲဒါတွေက သင့်ရဲ့ command တွေကို `list` နဲ့ screen မှာထုတ်ပြတဲ့အချိန်မှာ အသုံးပြုမှာပါ။ - -သင့် command excute ဖြစ်သွားပြီဆိုရင် `fire` method ကိုခေါ်ပါ့မယ်။ ဒီ method မှာသင်ကြိုက်တဲ့ command logic ကိုထည့်နိုင်တယ်။ - -### Arguments & Options - -The `getArguments` and `getOptions` methods are where you may define any arguments or options your command receives. - -`getArguments` နဲ့ `getOptions` methods တွေကို သင့် command ကနေလက်ခံရရှိတဲ့ မည်သည့် arguments ဒါမှမဟုတ် options မဆို သတ်မှတ်နိုင်ပါတယ်။ ဒီ methods နှစ်ခုက commands တွေကို array တစ်ခု return ပြန်ပါတယ်၊ အဲ့ဒီ့ array က array options တွေကို list တစ်ခုပုံစံနဲ့ ဖော်ပြထားပါတယ်။ - -`arguments` တွေကို defining လုပ်တဲ့အချိန်မှာ array definition values တွေကို အောက်မှာပြထားသလိုကိုယ်စားပြုပါတယ် - - - array($name, $mode, $description, $defaultValue) - -argument `mode` တွေက `InputArgument::REQUIRED` or `InputArgument::OPTIONAL` တစ်ခုခုဖြစ်လိမ့်မယ်။ - -`options` တွေကိုသတ်မှတ်တဲ့အချိန်မှာ array definition values တွေကို အောက်မှာပြထားသလိုကိုယ်စားပြုပါတယ် - - - array($name, $shortcut, $mode, $description, $defaultValue) - -options အတွက်... argument `mode` က `InputOption::VALUE_REQUIRED`, `InputOption::VALUE_OPTIONAL`, `InputOption::VALUE_IS_ARRAY`, `InputOption::VALUE_NONE` တွေဖြစ်လိမ့်မယ်။ - -`VALUES_IS_ARRAY` mode ကဘာကိုပြောတာလဲဆိုရင် command ကိုခေါ်တဲ့အချိန်မှာ နှစ်ကြိမ်သုံးလို့ရတယ်ဆိုတာကိုပြတာပါ - - - php artisan foo --option=bar --option=baz - -The `VALUE_NONE` option indicates that the option is simply used as a "switch": -`VALUE_NONE` ကဘာကိုပြောတာလဲဆိုရင် သင့်ရဲ့ option ကို "switch" အဖြစ်ရိုးရှင်းစွာ သုံးလို့ရတယ်ဆိုတာကိုပြတာပါ - - - php artisan foo --option - -### Retrieving Input - -ဘာလို့ သင့်ရဲ့ command က execute ဖြစ်တာလည်း၊ သင်သေချာပေါက် arguments နဲ့ options တွေကို application က accept လုပ်လိုက် တဲ့ values access လုပ်ဖို့လိုပါမယ် လို့ပါမယ် ဒါကိုလုပ်ဖို့ဆိုရင် သင့်အနေနဲ့ `argument` နဲ့ `option` method တွေကိုသုံးဖို့လိုပါလိမ့်မယ်။ - -#### Retrieving The Value Of A Command Argument - - $value = $this->argument('name'); - -#### Retrieving All Arguments - - $arguments = $this->argument(); - -#### Retrieving The Value Of A Command Option - - $value = $this->option('name'); - -#### Retrieving All Options - - $options = $this->option(); - -### Writing Output - -To send output to the console, you may use the `info`, `comment`, `question` and `error` methods. Each of these methods will use the appropriate ANSI colors for their purpose. - -Console ဆီကို output send ဖို့ရာအတွက် သင့်အနေနဲ့ `info`, `comment`, `question` နဲ့ `error` methods တွေကိုအသုံးပြုဖို့လိုပါလိမ့်မယ်။ ဒီ methods တစ်ခုချင်းဆီက သူတို့ရည်ရွယ်ချက်နဲ့သင့်လျော်တဲ့ ANSI colors တွေကို အသုံးပြုပါလိမ့်မယ်။ - -#### Sending Information To The Console - - $this->info('Display this on the screen'); - -#### Sending An Error Message To The Console - - $this->error('Something went wrong!'); - -### Asking Questions - -user input prompt အတွက် သင့်အနေနဲ့ `ask` နဲ့ `confirm` methods တွေကို အသုံးပြုနိုင်ပါတယ် - - -#### Asking The User For Input - - $name = $this->ask('What is your name?'); - -#### Asking The User For Secret Input - - $password = $this->secret('What is the password?'); - -#### Asking The User For Confirmation - - if ($this->confirm('Do you wish to continue? [yes|no]')) - { - // - } - -သင့်အနေနဲ့ default value ကိုု `confirm` method အဖြစ် သတ်မှတ်ထားနိုင်ပါတယ်၊ ဒါက `true` or `false` ဖြစ်သင့်ပါတယ်: - - $this->confirm($question, true); - - -## Registering Commands - -#### Registering An Artisan Command - -သင်ရဲ့ command ကပြီးသွားပြီ ဆိုရင် သင့်အနေနဲ့ Artisan နဲ့ register လုပ်ရပါမယ် ဒါမှ အသုံးပြုလို့ရမှာပါ။ ဒါကိုလည်း ထုံးစံအတိုင်းဘဲ `app/start/artisan.php` file မှာ လုပ်ရမှာပါ။ ဒီ file ထဲမှာ command ကို register လုပ်ဖို့ရာအတွက် `Artisan::add` method ကို အသုံးပြုသင့်ပါတယ် - - - Artisan::add(new CustomCommand); - -#### Registering A Command That Is In The IoC Container - -သင့် ရဲ့ command က application ရဲ့ [IoC container](ioc.md) ထဲမှာ Register လုပ်ထားတယ်ဆိုရင်... Arisan ကနေခေါ်နိုင်အောင် သင့်အနေဲ့ `Artisan::resolve` method ကို အသုံးပြုရပါ့မယ် - - - Artisan::resolve('binding.name'); - - -## Calling Other Commands - -တစ်ခါတစ်လေသင့် command ကနေအခြား command တစ်ခုခုကိုခေါ်ချင်မှာပေါ့... ဒါလည်းရပါတယ် `call` method နဲ့ခေါ်လိုက်ရုံပါဘဲ - - - $this->call('command:name', array('argument' => 'foo', '--option' => 'bar')); \ No newline at end of file diff --git a/configuration.md b/configuration.md index f885f96..a72764b 100644 --- a/configuration.md +++ b/configuration.md @@ -1,146 +1,100 @@ -# Configuration လုပ်ခြင်း +# Configuration -- [မိတ်ဆက်](#introduction) -- [Environment ပြင်ဆင်ခြင်း](#environment-configuration) -- [Provider ပြင်ဆင်ခြင်း](#provider-configuration) -- [အမှားခံ၊ အသိခံ၍ မရသော အချက်အလက်များအား ကာကွယ်ခြင်း](#protecting-sensitive-configuration) -- [Application အားပြုပြင်ထိန်းသိမ်းမှု အခြေအနေ](#maintenance-mode) +- [Introduction](#introduction) +- [Environment Configuration](#environment-configuration) + - [Determining The Current Environment](#determining-the-current-environment) +- [Accessing Configuration Values](#accessing-configuration-values) +- [Configuration Caching](#configuration-caching) +- [Maintenance Mode](#maintenance-mode) -## မိတ်ဆက် +## Introduction -Laravel framework မှာရှိတဲ့ configuration ဖိုင်အားလုံးကို `app/config` လမ်းကြောင်းအောက်မှာသိမ်းထားပါတယ်။ ဖိုင်အားလုံးမှာပါတဲ့ option တစ်ခုချင်းစီအတွက် documentation မှာ ရေးထားပီးသားပါ။ အသုံးပြုနိုင်တဲ့ options တွေကို documentation နဲ့တွဲပြီး လေ့လာ နိုင်ပါတယ်။ - -Application run နေတဲ့အချိန်တွေမှာ configuration values တွေကို အသုံးပြုဖို့လိုအပ်လာရင် `Config` class ကိုအသုံးပြုပြီး ဆွဲယူနိုင်ပါတယ်။ - -#### Configuration Value များကို အသုံးပြုခြင်း - - Config::get('app.timezone'); - -ဆွဲယူအသုံးပြုလိုက်တဲ့ configuration option မရှိတဲ့အခြေအနေအတွက် default value ကို return ပြန်အောင် သတ်မှတ်ပေးထားနိုင်ပါတယ်။ - - $timezone = Config::get('app.timezone', 'UTC'); - -#### Configuration value သတ်မှတ်ခြင်း - -Configuration ဖိုင်တွေထဲမှာရှိတဲ့ value တွေကို "dot” ကိုအသုံးပြုပြီး (eg. filename.value) access လုပ်နိုင်ပါတယ်။ Application run-time ကာလမှာ configuration တွေသတ်မှတ်ဖို့အတွက်လည်း အသုံးပြုနိုင်ပါတယ်။ - - Config::set('database.default', 'sqlite'); - -Applicastion run-time ကာလမှာ သတ်မှတ်ထားတဲ့ configuration values တွေဟာ app ရဲ့ လက်ရှိ request အပေါ်မှာပဲသက်ရောက်မှုရှိပါတယ်။ နောက်ပိုင်းထပ်ဖြစ်လာမဲ့ requests တွေအထိ ယူဆောင်သွားမှာမဟုတ်ပါဘူး +All of the configuration files for the Laravel framework are stored in the `config` directory. Each option is documented, so feel free to look through the files and get familiar with the options available to you. -## Environment ပြင်ဆင်ခြင်း - -Application run နေတဲ့ environment အပေါ်အခြေခံပီး configuration ဖိုင်တွေ သတ်မှတ်ထားခြင်းဟာ အထောက်အကူ အများကြီးဖြစ်စေပါတယ်။ ဥပမာ - ကိုယ့်ရဲ့ local machine ပေါ်မှာ မတူညီတဲ့ cache driver တွေအသုံးပြုချင်တယ်ဆိုရင် ဒီ environment based configuration ကိုအသုံးပြုရုံနဲ့ လွယ်ကူ ပြီးမြောက်စေနိုင်ပါတယ်။ - -`config` ဖိုဒါထဲမှာ ကိုယ့်ရဲ့ environmen လိုက်ဖက်မဲ့ directory တစ်ခုကို ဆောက်လိုက်ပါ။ ဥပမာ - `local`။ ပြီးရင် အဲ့ဒီ environment အတွက် override လုပ်သွားမဲ့ config တွေ၊ ထပ်မံသတ်မှတ်ချင်တဲ့ options တွေကို configuration ဖိုင်တွေပြုလုပ်ပီးသတ်မှတ်နိုင်ပါပြီ။ ဥပမာ - local environment အတွက် cache driver ကို override လုပ်ချင်တယ်ဆိုရင်၊ `app/config/local` ဖိုဒါထဲမှာ `cache.php` ဖိုင်ဆောက်ပီး အောက်မှာပေးထားတဲ့ code တွေနဲ့ ပြုလုပ်လိုက်ပါ။ +## Environment Configuration - 'file', +> {tip} You may also create a `.env.testing` file. This file will override values from the `.env` file when running PHPUnit tests or executing Artisan commands with the `--env=testing` option. - ); +#### Retrieving Environment Configuration -> **သတိပြုရန်:** `testing` ဆိုတဲ့ အမည်နဲ့ environment name ကို မသတ်မှတ်ပါနဲ့။ အဲ့ဒီအမည်ဟာ unit testing အတွက် သီးသန့်သတ်မှတ်ထားတဲ့ အမည်ဖြစ်ပါတယ်။ +All of the variables listed in this file will be loaded into the `$_ENV` PHP super-global when your application receives a request. However, you may use the `env` helper to retrieve values from these variables in your configuration files. In fact, if you review the Laravel configuration files, you will notice several of the options already using this helper: -base configuration ဖိုင်မှာပါတဲ့ option အားလုံးကို ပြန်လည်သတ်မှတ်ပေးဖို့ မလိုအပ်ပါ လိုအပ်ပြီး ကိုယ့်အနေနဲ့ override လုပ်ချင်တဲ့ option တွေကိုသာသတ်မှတ်ပေးရန်။ Base configuration files တွေကို environment configuration files တွေက "cascade” လုပ်သွားပါလိမ့်မယ်။ + 'debug' => env('APP_DEBUG', false), -ပြီးရင်တော့ ဘယ် environment မှာ run နေတယ်ဆိုတာ framework ကနေ သိနိုင်ဖို့အတွက် သတ်မှတ်ထားပေးရမှာပါ။ Default environment ကတော့ `production` ဖြစ်ပါတယ်။ အခြား environment တွေအတွက် setup ပြုလုပ်ရမဲ့ နေရာက root directory အောက်မှာရှိတဲ့ `bootstrap/start.php` ဖိုင်ထဲမှာပြုလုပ်ပေးရပါမယ်။ အဲ့ဒီဖိုင်ထဲမှာရှိတဲ့ `$app->detectEnvironment` ဆိုတဲ့ method ထဲကို သတ်မှတ်ထားတဲ့ environment တွေပါတဲ့ array တစ်ခု passing လုပ်ထားပါတယ်။ အဲ့ဒီ array ကိုအသုံးပြုပြီး လက်ရှိ environment ကို ဆုံးဖြတ်တာဖြစ်ပါတယ်။ လိုအပ်လာလို့ရှိရင် အဲ့ဒီ array ထဲကို နောက်ထပ် environment တွေ ထပ်ထည့်နိုင်ပါတယ်။ +The second value passed to the `env` function is the "default value". This value will be used if no environment variable exists for the given key. - detectEnvironment(array( +If you are developing with a team, you may wish to continue including a `.env.example` file with your application. By putting place-holder values in the example configuration file, other developers on your team can clearly see which environment variables are needed to run your application. - 'local' => array('your-machine-name'), + +### Determining The Current Environment - )); +The current application environment is determined via the `APP_ENV` variable from your `.env` file. You may access this value via the `environment` method on the `App` [facade](/docs/{{version}}/facades): -အပေါ်မှာပြထားတဲ့ ဥပမာမှာ `local` က environment အမည်ဖြစ်ပြီး `your-machine-name` က server ရဲ့ hostname ဖြစ်ပါတယ်။ Linux နဲ့ Mac ကွန်ပျူတာတွေမှာဆိုရင် `hostname` ဆိုတဲ့ terminal command ကိုအသုံးပြုပြီး hostname ကိုသတ်မှတ်ပေးနိုင်ပါတယ်။ + $environment = App::environment(); -အကယ်၍ ပိုပြီးထိရောက်တဲ့ environment သိရှိမှုကို လိုအပ်တယ်ဆိုရင်တော့ `detectEnvironment` method ထဲကို ကိုယ်လိုအပ်သလိုအသုံးပြုနိုင်တဲ့ environment သိရှိမှုတွေကိုပြုလုပ်ပေးနိုင်မဲ့ `Closure` တစ်ခုကို passing ပေးဖို့လိုအပ်ပါတယ်။ +You may also pass arguments to the `environment` method to check if the environment matches a given value. The method will return `true` if the environment matches any of the given values: - $env = $app->detectEnvironment(function() - { - return $_SERVER['MY_LARAVEL_ENV']; - }); + if (App::environment('local')) { + // The environment is local + } -#### Application ရဲ့ လက်ရှိ Environment ကိုအသုံးပြုခြင်း။ + if (App::environment('local', 'staging')) { + // The environment is either local OR staging... + } -Application ရဲ့ လက်ရှိအသုံးပြုနေတဲ့ environment ကို `environment` method ကိုအသုံးပြုပြီး ရယူနိုင်ပါတယ်။ + +## Accessing Configuration Values - $environment = App::environment(); +You may easily access your configuration values using the global `config` helper function from anywhere in your application. The configuration values may be accessed using "dot" syntax, which includes the name of the file and option you wish to access. A default value may also be specified and will be returned if the configuration option does not exist: -ကိုယ်အသုံးပြုချင်တဲ့ environment ဟုတ်/မဟုတ် ကိုလည်း `environment` method ထဲကို arguments တွေ passing ပေးပြီး စစ်ကြည့်နိုင်ပါတယ်။ + $value = config('app.timezone'); - if (App::environment('local')) - { - // Local environment ဖြစ်တယ် - } +To set configuration values at runtime, pass an array to the `config` helper: - if (App::environment('local', 'staging')) - { - //Local သို့မဟုတ် staging environment ဖြစ်တယ် - } + config(['app.timezone' => 'America/Chicago']); - -### Provider ပြင်ဆင်ခြင်း + +## Configuration Caching -Environment configuration ကို အသုံးပြုပြီဆိုလို့ရှိရင်၊ ကိုယ့်ရဲ့ ပင်မ `app` configuration ဖိုင်ထဲမှာ environment [service providers](ioc#service-providers.md) ကိုထည့်ပေါင်းထည့်ဖို့ လိုအပ်လာတဲ့ အခြေအနေတွေ ရှိလာနိုင်ပါတယ်။ အကယ်၍ ကိုယ်က ထပ်ပေါင်းထည့်ထားတယ်ဆိုလို့ရှိရင်, the environment `app` providers are overriding the providers in your primary `app` configuration file ဆိုပြီး သတိပေးပါလိမ့်မယ်။ အဲ့လိုအခြေအနေမျိုးမှာ providers ကို မရမကထပ်ပေါင်းထည့်စေဖို့အတွက် `append_config` ဆိုတဲ့ helper method ကို ကိုယ့်ရဲ့ environment `app` configuration ဖိုင်ထဲမှာ အသုံးပြုနိုင်ပါတယ်။ +To give your application a speed boost, you should cache all of your configuration files into a single file using the `config:cache` Artisan command. This will combine all of the configuration options for your application into a single file which will be loaded quickly by the framework. - 'providers' => append_config(array( - 'LocalOnlyServiceProvider', - )) +You should typically run the `php artisan config:cache` command as part of your production deployment routine. The command should not be run during local development as configuration options will frequently need to be changed during the course of your application's development. - -## အမှားခံ၊ အသိခံ၍ မရသော အချက်အလက်များအား ကာကွယ်ခြင်း +> {note} If you execute the `config:cache` command during your deployment process, you should be sure that you are only calling the `env` function from within your configuration files. -အမှန်တကယ်အသုံးပြုမဲ့ application တွေအတွက်၊ ကိုယ့်ရဲ့ အမှားမခံ၊ အသိခံလို့ မရတဲ့ configuration တွေကို configuration ဖိုင်ထဲမှာ မသိမ်းပဲနဲ့ အခြားတစ်နေရာမှာထားတာက ပိုပြီးသင့်တော်ပါတယ်။ ဘယ်လိုအမျိုးအစားတွေလဲဆိုတော့ database passwords, Stripe API keys, and encryption keys စတာတွေကို ဖြစ်နိုင်လို့ရှိရင် configuration ဖိုင်ထဲမှာမသိမ်းသင့်ပါဘူး။ ဒါဆိုဘယ်နေရာမှာသိမ်းမလဲ? အဲ့ဒီအတွက် Laravel ကဖြေရှင်းပေးပြီးသားဖြစ်ပါတယ်။ အဲ့ဒီလို configuration အမျိုးအစားတွေအတွက် "dot" files တွေကိုအသုံးပြုပြီး ကာကွယ်ထားနိုင်ပါတယ်။ - -ပထမဆုံးအနေနဲ့ ကိုယ့်ရဲ့စက်ဟာ local မှာ run နေတာပါဆိုတာကို application ကသိအောင် [configure](configuration#environment-configuration.md) လုပ်ပေးရပါမယ်။ ပြီးရင် `.env.local.php` ဆိုတဲ့ ဖိုင်အသစ်ကို `composer.json` ဖိုင်ရှိတဲ့ ဖိုဒါအောက်မှာ ဆောက်ပေးလိုက်ပါ။ အဲ့ဒီ `.env.local.php` ဖိုင်ဟာ အခြား laravel configuration ဖိုင်တွေလိုပဲ key-value pairs ဖြစ်တဲ့ array တစ်ခု return ပြန်ရပါမယ်။ - - 'super-secret-sauce', - - ); - -အဲ့ဒီ ဖိုင်ထဲကနေ return ပြန်လာတဲ့ key-value pairs တွေဟာ PHP "superglobals" တွေဖြစ်တဲ့ `$_ENV` နဲ့ `$_SERVER` တွေဆီကို auto ရောက်သွားပါလိမ့်မယ်။ အဲ့ဒီ "superglobals" တွေကနေတစ်ဆင့် ကိုယ့်ရဲ့ configuration ဖိုင်ထဲမှာ ပြန်လည်အသုံးပြုနိုင်ပြီဖြစ်ပါတယ်။ - - 'key' => $_ENV['TEST_STRIPE_KEY'] - -သေချာအောင်လုပ်ဖို့လိုအပ်တာတစ်ခုက အဲ့ဒီ `.env.local.php` ဖိုင်ကို `.gitignore` လုပ်ထားပေးရပါမယ်။ အဲ့ဒီတော့မှ ကိုယ့်ရဲ့ team မှာရှိတဲ့ကျန်တဲ့ developers တွေဟာ သူတို့ရဲ့ ကိုယ်ပိုင် local configuration တွေကိုပြုလုပ်နိုင်မည့်အပြင် ကိုယ့်ရဲ့ sensitive configuration တွေကိုလဲ source control မှာမပါအောင် ကာကွယ်ပြီးသားဖြစ်မှာပါ။ + +## Maintenance Mode -Production environment အတွက်လည်း လိုအပ်တဲ့ configuration တွေပါတဲ့ `.env.php` ဖိုင်ကို project root ဖိုဒါထဲမှာ ဆောက်လိုက်ပါ။ `.env.local.php` ဖိုင်လိုပဲ production environment မှာ အသုံးပြုမဲ့`.env.php` ဖိုင်ဟာ source control ထဲမှာ မပါသင့်ပါဘူး။ +When your application is in maintenance mode, a custom view will be displayed for all requests into your application. This makes it easy to "disable" your application while it is updating or when you are performing maintenance. A maintenance mode check is included in the default middleware stack for your application. If the application is in maintenance mode, a `MaintenanceModeException` will be thrown with a status code of 503. -> **သတိပြုရန်:** Application ကနေ support လုပ်တဲ့ environment တစ်ခုချင်းစီအတွက် `.env` ဖိုင်တွေ တည်ဆောက်လာနိုင်ပါတယ်။ ဥပမာ - `development` environment အတွက်ဆိုရင် `.env.development.php` ဖိုင်က ရှိနေလို့ရှိရင် load လုပ်သွားပါလိမ့်မယ်။ +To enable maintenance mode, simply execute the `down` Artisan command: - -## Application အားပြုပြင်ထိန်းသိမ်းမှုအခြေအနေ + php artisan down -Application ဟာ ပြုပြင်ထိန်းသိမ်းမှု ပြုလုပ်တဲ့ အခြေအနေမှာ ရှိနေမယ်ဆိုရင် application မှာရှိတဲ့ route အားလုံးအတွက် ကြိုတင်ပြုလုပ်ထားနိုင်တဲ့ စိတ်ကြိုက် မြင်ကွင်း(view) ကိုပြပေးပါလိမ့်မယ်။ ပြုပြင်ထိန်းသိမ်းမှုပြုလုပ်နေရင်ပဲဖြစ်ဖြစ်၊ update လုပ်နေရင်ပဲဖြစ်ဖြစ် application ကို လွယ်လွယ်ကူကူပဲ disable လုပ်ထားနိုင်ပါတယ်။ `app/start/global.php` ဖိုင်ထဲမှာရှိပြီးသားဖြစ်တဲ့ `App::down` ဆိုတဲ့ method ကိုခေါ်သုံးလိုက်ရုံပဲ။ အဲ့ဒီ method ကနေပြန်လာတဲ့ response ကို users တွေဆီကိုပို့ပေးပါလိမ့်မယ်။ +You may also provide `message` and `retry` options to the `down` command. The `message` value may be used to display or log a custom message, while the `retry` value will be set as the `Retry-After` HTTP header's value: -ပြုပြင်ထိန်းသိမ်းမှုပြုလုပ်နေပါတယ်ဆိုတဲ့ အခြေအနေကိုထားချင်တယ်ဆိုရင် `down` ဆိုတဲ့ Artisan command ကို အသုံးပြုနိုင်ပါတယ်။ + php artisan down --message="Upgrading Database" --retry=60 - php artisan down +To disable maintenance mode, use the `up` command: -ထိန်းသိမ်းမှုပြုလုပ်ပြီးသွားလို့ application ကိုပြန်ပြီး အသက်သွင်းချင်ရင် `up` ဆိုတဲ့ Artisan command ကို အသုံးပြုနိုင်ပါတယ်။ + php artisan up - php artisan up +#### Maintenance Mode Response Template -ထိန်းသိမ်းမှုပြုလုပ်နေတဲ့အခြေအနေအတွက် စိတ်ကြိုက် မြင်ကွင်း (view) သတ်မှတ်ချင်တယ်ဆိုရင်တော့ အောက်မှာပြထားသလိုပဲ `app/start/global.php` ဖိုင်ထဲမှာ နှစ်သက်သလို သွားရောက်ပြင်ဆင်နိုင်ပါတယ်။ +The default template for maintenance mode responses is located in `resources/views/errors/503.blade.php`. You are free to modify this view as needed for your application. - App::down(function() - { - return Response::view('maintenance', array(), 503); - }); +#### Maintenance Mode & Queues -အကယ်၍ `down` method ထဲကို Closure တစ်ခု passing ပေးလိုက်ရင်တော့ `NULL` ပဲ return ပြန်လာပြီး အဲ့ဒီ request မှာပါတဲ့ maintenance mode ကို ignore လုပ်သွားပါလိမ့်မယ်။ +While your application is in maintenance mode, no [queued jobs](/docs/{{version}}/queues) will be handled. The jobs will continue to be handled as normal once the application is out of maintenance mode. -### Maintenance Mode နှင့် Queues +#### Alternatives To Maintenance Mode -Application ဟာ maintenance mode မှာ ရှိနေစဉ်အတွင်း [queue jobs](queues.md) တွေကို ကိုင်တွယ်ဖြေရှင်းမှာမဟုတ်ပါဘူး။ Application ဟာ ပုံမှန်အခြေအနေ ကိုပြန်ရောက်ပီဆိုတော့မှ ပြန်လည်ကိုင်တွယ်ဖြေရှင်းပေးမှာဖြစ်ပါတယ်။ \ No newline at end of file +Since maintenance mode requires your application to have several seconds of downtime, consider alternatives like [Envoyer](https://envoyer.io) to accomplish zero-downtime deployment with Laravel. diff --git a/container.md b/container.md new file mode 100644 index 0000000..5431105 --- /dev/null +++ b/container.md @@ -0,0 +1,249 @@ +# Service Container + +- [Introduction](#introduction) +- [Binding](#binding) + - [Binding Basics](#binding-basics) + - [Binding Interfaces To Implementations](#binding-interfaces-to-implementations) + - [Contextual Binding](#contextual-binding) + - [Tagging](#tagging) +- [Resolving](#resolving) + - [The Make Method](#the-make-method) + - [Automatic Injection](#automatic-injection) +- [Container Events](#container-events) + + +## Introduction + +The Laravel service container is a powerful tool for managing class dependencies and performing dependency injection. Dependency injection is a fancy phrase that essentially means this: class dependencies are "injected" into the class via the constructor or, in some cases, "setter" methods. + +Let's look at a simple example: + + users = $users; + } + + /** + * Show the profile for the given user. + * + * @param int $id + * @return Response + */ + public function show($id) + { + $user = $this->users->find($id); + + return view('user.profile', ['user' => $user]); + } + } + +In this example, the `UserController` needs to retrieve users from a data source. So, we will **inject** a service that is able to retrieve users. In this context, our `UserRepository` most likely uses [Eloquent](/docs/{{version}}/eloquent) to retrieve user information from the database. However, since the repository is injected, we are able to easily swap it out with another implementation. We are also able to easily "mock", or create a dummy implementation of the `UserRepository` when testing our application. + +A deep understanding of the Laravel service container is essential to building a powerful, large application, as well as for contributing to the Laravel core itself. + + +## Binding + + +### Binding Basics + +Almost all of your service container bindings will be registered within [service providers](/docs/{{version}}/providers), so most of these examples will demonstrate using the container in that context. + +> {tip} There is no need to bind classes into the container if they do not depend on any interfaces. The container does not need to be instructed on how to build these objects, since it can automatically resolve these objects using reflection. + +#### Simple Bindings + +Within a service provider, you always have access to the container via the `$this->app` property. We can register a binding using the `bind` method, passing the class or interface name that we wish to register along with a `Closure` that returns an instance of the class: + + $this->app->bind('HelpSpot\API', function ($app) { + return new HelpSpot\API($app->make('HttpClient')); + }); + +Note that we receive the container itself as an argument to the resolver. We can then use the container to resolve sub-dependencies of the object we are building. + +#### Binding A Singleton + +The `singleton` method binds a class or interface into the container that should only be resolved one time. Once a singleton binding is resolved, the same object instance will be returned on subsequent calls into the container: + + $this->app->singleton('HelpSpot\API', function ($app) { + return new HelpSpot\API($app->make('HttpClient')); + }); + +#### Binding Instances + +You may also bind an existing object instance into the container using the `instance` method. The given instance will always be returned on subsequent calls into the container: + + $api = new HelpSpot\API(new HttpClient); + + $this->app->instance('HelpSpot\Api', $api); + +#### Binding Primitives + +Sometimes you may have a class that receives some injected classes, but also needs an injected primitive value such as an integer. You may easily use contextual binding to inject any value your class may need: + + $this->app->when('App\Http\Controllers\UserController') + ->needs('$variableName') + ->give($value); + + +### Binding Interfaces To Implementations + +A very powerful feature of the service container is its ability to bind an interface to a given implementation. For example, let's assume we have an `EventPusher` interface and a `RedisEventPusher` implementation. Once we have coded our `RedisEventPusher` implementation of this interface, we can register it with the service container like so: + + $this->app->bind( + 'App\Contracts\EventPusher', + 'App\Services\RedisEventPusher' + ); + +This statement tells the container that it should inject the `RedisEventPusher` when a class needs an implementation of `EventPusher`. Now we can type-hint the `EventPusher` interface in a constructor, or any other location where dependencies are injected by the service container: + + use App\Contracts\EventPusher; + + /** + * Create a new class instance. + * + * @param EventPusher $pusher + * @return void + */ + public function __construct(EventPusher $pusher) + { + $this->pusher = $pusher; + } + + +### Contextual Binding + +Sometimes you may have two classes that utilize the same interface, but you wish to inject different implementations into each class. For example, two controllers may depend on different implementations of the `Illuminate\Contracts\Filesystem\Filesystem` [contract](/docs/{{version}}/contracts). Laravel provides a simple, fluent interface for defining this behavior: + + use Illuminate\Support\Facades\Storage; + use App\Http\Controllers\PhotoController; + use App\Http\Controllers\VideoController; + use Illuminate\Contracts\Filesystem\Filesystem; + + $this->app->when(PhotoController::class) + ->needs(Filesystem::class) + ->give(function () { + return Storage::disk('local'); + }); + + $this->app->when(VideoController::class) + ->needs(Filesystem::class) + ->give(function () { + return Storage::disk('s3'); + }); + + +### Tagging + +Occasionally, you may need to resolve all of a certain "category" of binding. For example, perhaps you are building a report aggregator that receives an array of many different `Report` interface implementations. After registering the `Report` implementations, you can assign them a tag using the `tag` method: + + $this->app->bind('SpeedReport', function () { + // + }); + + $this->app->bind('MemoryReport', function () { + // + }); + + $this->app->tag(['SpeedReport', 'MemoryReport'], 'reports'); + +Once the services have been tagged, you may easily resolve them all via the `tagged` method: + + $this->app->bind('ReportAggregator', function ($app) { + return new ReportAggregator($app->tagged('reports')); + }); + + +## Resolving + + +#### The `make` Method + +You may use the `make` method to resolve a class instance out of the container. The `make` method accepts the name of the class or interface you wish to resolve: + + $api = $this->app->make('HelpSpot\API'); + +If you are in a location of your code that does not have access to the `$app` variable, you may use the global `resolve` helper: + + $api = resolve('HelpSpot\API'); + + +#### Automatic Injection + +Alternatively, and importantly, you may simply "type-hint" the dependency in the constructor of a class that is resolved by the container, including [controllers](/docs/{{version}}/controllers), [event listeners](/docs/{{version}}/events), [queue jobs](/docs/{{version}}/queues), [middleware](/docs/{{version}}/middleware), and more. In practice, this is how most of your objects should be resolved by the container. + +For example, you may type-hint a repository defined by your application in a controller's constructor. The repository will automatically be resolved and injected into the class: + + users = $users; + } + + /** + * Show the user with the given ID. + * + * @param int $id + * @return Response + */ + public function show($id) + { + // + } + } + + +## Container Events + +The service container fires an event each time it resolves an object. You may listen to this event using the `resolving` method: + + $this->app->resolving(function ($object, $app) { + // Called when container resolves object of any type... + }); + + $this->app->resolving(HelpSpot\API::class, function ($api, $app) { + // Called when container resolves objects of type "HelpSpot\API"... + }); + +As you can see, the object being resolved will be passed to the callback, allowing you to set any additional properties on the object before it is given to its consumer. diff --git a/contracts.md b/contracts.md new file mode 100644 index 0000000..4d8a820 --- /dev/null +++ b/contracts.md @@ -0,0 +1,205 @@ +# Contracts + +- [Introduction](#introduction) + - [Contracts Vs. Facades](#contracts-vs-facades) +- [When To Use Contracts](#when-to-use-contracts) + - [Loose Coupling](#loose-coupling) + - [Simplicity](#simplicity) +- [How To Use Contracts](#how-to-use-contracts) +- [Contract Reference](#contract-reference) + + +## Introduction + +Laravel's Contracts are a set of interfaces that define the core services provided by the framework. For example, a `Illuminate\Contracts\Queue\Queue` contract defines the methods needed for queueing jobs, while the `Illuminate\Contracts\Mail\Mailer` contract defines the methods needed for sending e-mail. + +Each contract has a corresponding implementation provided by the framework. For example, Laravel provides a queue implementation with a variety of drivers, and a mailer implementation that is powered by [SwiftMailer](http://swiftmailer.org/). + +All of the Laravel contracts live in [their own GitHub repository](https://github.com/illuminate/contracts). This provides a quick reference point for all available contracts, as well as a single, decoupled package that may be utilized by package developers. + + +### Contracts Vs. Facades + +Laravel's [facades](/docs/{{version}}/facades) and helper functions provide a simple way of utilizing Laravel's services without needing to type-hint and resolve contracts out of the service container. In most cases, each facade has an equivalent contract. + +Unlike facades, which do not require you to require them in your class' constructor, contracts allow you to define explicit dependencies for your classes. Some developers prefer to explicitly define their dependencies in this way and therefore prefer to use contracts, while other developers enjoy the convenience of facades. + +> {tip} Most applications will be fine regardless of whether you prefer facades or contracts. However, if you are building a package, you should strongly consider using contracts since they will be easier to test in a package context. + + +## When To Use Contracts + +As discussed elsewhere, much of the decision to use contracts or facades will come down to personal taste and the tastes of your development team. Both contracts and facades can be used to create robust, well-tested Laravel applications. As long as you are keeping your class' responsibilities focused, you will notice very few practical differences between using contracts and facades. + +However, you may still have several questions regarding contracts. For example, why use interfaces at all? Isn't using interfaces more complicated? Let's distill the reasons for using interfaces to the following headings: loose coupling and simplicity. + + +### Loose Coupling + +First, let's review some code that is tightly coupled to a cache implementation. Consider the following: + + cache = $cache; + } + + /** + * Retrieve an Order by ID. + * + * @param int $id + * @return Order + */ + public function find($id) + { + if ($this->cache->has($id)) { + // + } + } + } + +In this class, the code is tightly coupled to a given cache implementation. It is tightly coupled because we are depending on a concrete Cache class from a package vendor. If the API of that package changes our code must change as well. + +Likewise, if we want to replace our underlying cache technology (Memcached) with another technology (Redis), we again will have to modify our repository. Our repository should not have so much knowledge regarding who is providing them data or how they are providing it. + +**Instead of this approach, we can improve our code by depending on a simple, vendor agnostic interface:** + + cache = $cache; + } + } + +Now the code is not coupled to any specific vendor, or even Laravel. Since the contracts package contains no implementation and no dependencies, you may easily write an alternative implementation of any given contract, allowing you to replace your cache implementation without modifying any of your cache consuming code. + + +### Simplicity + +When all of Laravel's services are neatly defined within simple interfaces, it is very easy to determine the functionality offered by a given service. **The contracts serve as succinct documentation to the framework's features.** + +In addition, when you depend on simple interfaces, your code is easier to understand and maintain. Rather than tracking down which methods are available to you within a large, complicated class, you can refer to a simple, clean interface. + + +## How To Use Contracts + +So, how do you get an implementation of a contract? It's actually quite simple. + +Many types of classes in Laravel are resolved through the [service container](/docs/{{version}}/container), including controllers, event listeners, middleware, queued jobs, and even route Closures. So, to get an implementation of a contract, you can just "type-hint" the interface in the constructor of the class being resolved. + +For example, take a look at this event listener: + + redis = $redis; + } + + /** + * Handle the event. + * + * @param OrderWasPlaced $event + * @return void + */ + public function handle(OrderWasPlaced $event) + { + // + } + } + +When the event listener is resolved, the service container will read the type-hints on the constructor of the class, and inject the appropriate value. To learn more about registering things in the service container, check out [its documentation](/docs/{{version}}/container). + + +## Contract Reference + +This table provides a quick reference to all of the Laravel contracts and their equivalent facades: + +Contract | References Facade +------------- | ------------- +[Illuminate\Contracts\Auth\Factory](https://github.com/illuminate/contracts/blob/{{version}}/Auth/Factory.php) | Auth +[Illuminate\Contracts\Auth\PasswordBroker](https://github.com/illuminate/contracts/blob/{{version}}/Auth/PasswordBroker.php) | Password +[Illuminate\Contracts\Bus\Dispatcher](https://github.com/illuminate/contracts/blob/{{version}}/Bus/Dispatcher.php) | Bus +[Illuminate\Contracts\Broadcasting\Broadcaster](https://github.com/illuminate/contracts/blob/{{version}}/Broadcasting/Broadcaster.php) |   +[Illuminate\Contracts\Cache\Repository](https://github.com/illuminate/contracts/blob/{{version}}/Cache/Repository.php) | Cache +[Illuminate\Contracts\Cache\Factory](https://github.com/illuminate/contracts/blob/{{version}}/Cache/Factory.php) | Cache::driver() +[Illuminate\Contracts\Config\Repository](https://github.com/illuminate/contracts/blob/{{version}}/Config/Repository.php) | Config +[Illuminate\Contracts\Container\Container](https://github.com/illuminate/contracts/blob/{{version}}/Container/Container.php) | App +[Illuminate\Contracts\Cookie\Factory](https://github.com/illuminate/contracts/blob/{{version}}/Cookie/Factory.php) | Cookie +[Illuminate\Contracts\Cookie\QueueingFactory](https://github.com/illuminate/contracts/blob/{{version}}/Cookie/QueueingFactory.php) | Cookie::queue() +[Illuminate\Contracts\Encryption\Encrypter](https://github.com/illuminate/contracts/blob/{{version}}/Encryption/Encrypter.php) | Crypt +[Illuminate\Contracts\Events\Dispatcher](https://github.com/illuminate/contracts/blob/{{version}}/Events/Dispatcher.php) | Event +[Illuminate\Contracts\Filesystem\Cloud](https://github.com/illuminate/contracts/blob/{{version}}/Filesystem/Cloud.php) |   +[Illuminate\Contracts\Filesystem\Factory](https://github.com/illuminate/contracts/blob/{{version}}/Filesystem/Factory.php) | File +[Illuminate\Contracts\Filesystem\Filesystem](https://github.com/illuminate/contracts/blob/{{version}}/Filesystem/Filesystem.php) | File +[Illuminate\Contracts\Foundation\Application](https://github.com/illuminate/contracts/blob/{{version}}/Foundation/Application.php) | App +[Illuminate\Contracts\Hashing\Hasher](https://github.com/illuminate/contracts/blob/{{version}}/Hashing/Hasher.php) | Hash +[Illuminate\Contracts\Logging\Log](https://github.com/illuminate/contracts/blob/{{version}}/Logging/Log.php) | Log +[Illuminate\Contracts\Mail\MailQueue](https://github.com/illuminate/contracts/blob/{{version}}/Mail/MailQueue.php) | Mail::queue() +[Illuminate\Contracts\Mail\Mailer](https://github.com/illuminate/contracts/blob/{{version}}/Mail/Mailer.php) | Mail +[Illuminate\Contracts\Queue\Factory](https://github.com/illuminate/contracts/blob/{{version}}/Queue/Factory.php) | Queue::driver() +[Illuminate\Contracts\Queue\Queue](https://github.com/illuminate/contracts/blob/{{version}}/Queue/Queue.php) | Queue +[Illuminate\Contracts\Redis\Database](https://github.com/illuminate/contracts/blob/{{version}}/Redis/Database.php) | Redis +[Illuminate\Contracts\Routing\Registrar](https://github.com/illuminate/contracts/blob/{{version}}/Routing/Registrar.php) | Route +[Illuminate\Contracts\Routing\ResponseFactory](https://github.com/illuminate/contracts/blob/{{version}}/Routing/ResponseFactory.php) | Response +[Illuminate\Contracts\Routing\UrlGenerator](https://github.com/illuminate/contracts/blob/{{version}}/Routing/UrlGenerator.php) | URL +[Illuminate\Contracts\Support\Arrayable](https://github.com/illuminate/contracts/blob/{{version}}/Support/Arrayable.php) |   +[Illuminate\Contracts\Support\Jsonable](https://github.com/illuminate/contracts/blob/{{version}}/Support/Jsonable.php) |   +[Illuminate\Contracts\Support\Renderable](https://github.com/illuminate/contracts/blob/{{version}}/Support/Renderable.php) |   +[Illuminate\Contracts\Validation\Factory](https://github.com/illuminate/contracts/blob/{{version}}/Validation/Factory.php) | Validator::make() +[Illuminate\Contracts\Validation\Validator](https://github.com/illuminate/contracts/blob/{{version}}/Validation/Validator.php) |   +[Illuminate\Contracts\View\Factory](https://github.com/illuminate/contracts/blob/{{version}}/View/Factory.php) | View::make() +[Illuminate\Contracts\View\View](https://github.com/illuminate/contracts/blob/{{version}}/View/View.php) |   diff --git a/contributing.md b/contributing.md index f7af0d9..e68c3d3 100644 --- a/contributing.md +++ b/contributing.md @@ -1,17 +1,3 @@ -# ပူးပေါင်းပါဝင်မှု လမ်းညွန် +# Contribution Guidelines -###ဘာသာပြန်ခြင်း - - - ကျွန်တော်တို့ကို ပူးပေါင်းပါဝင် ကူညီပြီးဘာသာပြန်ချင်တယ်ဆိုရင် - [docs](https://github.com/Laravel-Myanmar/docs) ကိုဦးစွာ Fork လုပ်ပါ၊ - - - ဘယ်အပိုင်းကို ဘာသာပြန်မည်ဆိုတာကို [Facebook](https://www.facebook.com/groups/250409601822202/) မှာပြောပေးပါ။ (Fork - လုပ်ပြီးဘာသာပြန်နေတုန်းအခြားတစ်ယောက်ယောက်ကပါဘာသာပြန်နေတာမျိုးဖြစ်မှာစိုးလို့ပါ) - - - သင်ဘာသာပြန်မည့် File ကိုဘာသာပြန်ပါ။ ဘာသာပြန်ပြီးရင် မူရင်း repo ဆီက - [pull request](https://github.com/Laravel-Myanmar/docs/pulls) တောင်းပါ။ (pull request တောင်းတာကို မြန်မြန် accept - လုပ်စေချင်တယ်ဆိုရင်[Facebook]( https://www.facebook.com/groups/250409601822202/) မှာပါတင်ပေးပါ) - -###ဘာသာပြန်အဆင်ပြေမှူနှင့် စာလုံးပေါင်းအမှား - -ဘာသာပြန်ထားတာတွေ ကိုဦးစွာဖတ်ပါ။ ဘာသာပြန်အဆင်ပြေမှူ နဲ့ စာလုံးပေါင်း အမှားတွေကို စစ်ပါ။ ဘာသာပြန်အဆင်ပြေမှူမရှိတာတို့ စာလုံးပေါင်းအမှားတွေတွေ့ရင် GitHub မှာ [issue](https://github.com/Laravel-Myanmar/docs/issues) တင်ပေးပါ။(အမှားတွေကို အမြန်ဆုံး စစ်ပေးဖို့ [Facebook](https://www.facebook.com/groups/250409601822202/) မှာပါတင်ပေးပါ) +If you are submitting documentation for the **current stable release**, submit it to the corresponding branch. For example, documentation for Laravel 5.1 would be submitted to the `5.1` branch. Documentation intended for the next release of Laravel should be submitted to the `master` branch. \ No newline at end of file diff --git a/contributions.md b/contributions.md new file mode 100644 index 0000000..9c94c09 --- /dev/null +++ b/contributions.md @@ -0,0 +1,85 @@ +# Contribution Guide + +- [Bug Reports](#bug-reports) +- [Core Development Discussion](#core-development-discussion) +- [Which Branch?](#which-branch) +- [Security Vulnerabilities](#security-vulnerabilities) +- [Coding Style](#coding-style) + - [PHPDoc](#phpdoc) + - [StyleCI](#styleci) + + +## Bug Reports + +To encourage active collaboration, Laravel strongly encourages pull requests, not just bug reports. "Bug reports" may also be sent in the form of a pull request containing a failing test. + +However, if you file a bug report, your issue should contain a title and a clear description of the issue. You should also include as much relevant information as possible and a code sample that demonstrates the issue. The goal of a bug report is to make it easy for yourself - and others - to replicate the bug and develop a fix. + +Remember, bug reports are created in the hope that others with the same problem will be able to collaborate with you on solving it. Do not expect that the bug report will automatically see any activity or that others will jump to fix it. Creating a bug report serves to help yourself and others start on the path of fixing the problem. + +The Laravel source code is managed on Github, and there are repositories for each of the Laravel projects: + +- [Laravel Framework](https://github.com/laravel/framework) +- [Laravel Application](https://github.com/laravel/laravel) +- [Laravel Documentation](https://github.com/laravel/docs) +- [Laravel Cashier](https://github.com/laravel/cashier) +- [Laravel Cashier for Braintree](https://github.com/laravel/cashier-braintree) +- [Laravel Envoy](https://github.com/laravel/envoy) +- [Laravel Homestead](https://github.com/laravel/homestead) +- [Laravel Homestead Build Scripts](https://github.com/laravel/settler) +- [Laravel Passport](https://github.com/laravel/passport) +- [Laravel Scout](https://github.com/laravel/scout) +- [Laravel Socialite](https://github.com/laravel/socialite) +- [Laravel Website](https://github.com/laravel/laravel.com) +- [Laravel Art](https://github.com/laravel/art) + + +## Core Development Discussion + +You may propose new features or improvements of existing Laravel behavior in the Laravel Internals [issue board](https://github.com/laravel/internals/issues). If you propose a new feature, please be willing to implement at least some of the code that would be needed to complete the feature. + +Informal discussion regarding bugs, new features, and implementation of existing features takes place in the `#internals` channel of the [LaraChat](https://larachat.co) Slack team. Taylor Otwell, the maintainer of Laravel, is typically present in the channel on weekdays from 8am-5pm (UTC-06:00 or America/Chicago), and sporadically present in the channel at other times. + + +## Which Branch? + +**All** bug fixes should be sent to the latest stable branch or to the current LTS branch (5.1). Bug fixes should **never** be sent to the `master` branch unless they fix features that exist only in the upcoming release. + +**Minor** features that are **fully backwards compatible** with the current Laravel release may be sent to the latest stable branch. + +**Major** new features should always be sent to the `master` branch, which contains the upcoming Laravel release. + +If you are unsure if your feature qualifies as a major or minor, please ask Taylor Otwell in the `#internals` channel of the [LaraChat](https://larachat.co) Slack team. + + +## Security Vulnerabilities + +If you discover a security vulnerability within Laravel, please send an email to Taylor Otwell at taylor@laravel.com. All security vulnerabilities will be promptly addressed. + + +## Coding Style + +Laravel follows the [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) coding standard and the [PSR-4](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md) autoloading standard. + + +### PHPDoc + +Below is an example of a valid Laravel documentation block. Note that the `@param` attribute is followed by two spaces, the argument type, two more spaces, and finally the variable name: + + /** + * Register a binding with the container. + * + * @param string|array $abstract + * @param \Closure|string|null $concrete + * @param bool $shared + * @return void + */ + public function bind($abstract, $concrete = null, $shared = false) + { + // + } + + +### StyleCI + +Don't worry if your code styling isn't perfect! [StyleCI](https://styleci.io/) will automatically merge any style fixes into the Laravel repository after pull requests are merged. This allows us to focus on the content of the contribution and not the code style. diff --git a/controllers.md b/controllers.md index 066c1ab..307df0d 100644 --- a/controllers.md +++ b/controllers.md @@ -1,224 +1,319 @@ -# Controllers များအကြောင်း +# Controllers +- [Introduction](#introduction) - [Basic Controllers](#basic-controllers) -- [Controller Filters](#controller-filters) -- [RESTful Controllers](#restful-controllers) + - [Defining Controllers](#defining-controllers) + - [Controllers & Namespaces](#controllers-and-namespaces) + - [Single Action Controllers](#single-action-controllers) +- [Controller Middleware](#controller-middleware) - [Resource Controllers](#resource-controllers) -- [Handling Missing Methods](#handling-missing-methods) + - [Partial Resource Routes](#restful-partial-resource-routes) + - [Naming Resource Routes](#restful-naming-resource-routes) + - [Naming Resource Route Parameters](#restful-naming-resource-route-parameters) + - [Supplementing Resource Controllers](#restful-supplementing-resource-controllers) +- [Dependency Injection & Controllers](#dependency-injection-and-controllers) +- [Route Caching](#route-caching) + + +## Introduction + +Instead of defining all of your request handling logic as Closures in route files, you may wish to organize this behavior using Controller classes. Controllers can group related request handling logic into a single class. Controllers are stored in the `app/Http/Controllers` directory. ## Basic Controllers -Application ရဲ့ Route ပိုင်းဆိုင်ရာအာလုံးကို `routes.php` တဖိုင်တည်းမှာ အားလုံး သတ်မှတ်ထားသလို ၊ အဲဒီ route တွေရဲ့ Action အားလုံးကို Controller က Class တွေနဲ့ ထိန်းချုပ်နိုင်မှာပါ။ Controllers က routes မှာသတ်မှတ်တဲ့ Action တွေကို ထိန်းချုပ်ပေးယုံ သာမက Framework တခုအတွက် အားသာချက်တခုဖြစ်တဲ့ [Automatic dependency injection][1] တွေပါအသုံးပြုနိုင်မှာပါ။ + +### Defining Controllers -Controllers ဖိုင်တွေကို ပုံမှန်အားဖြင့် `app/controllers` အောက်မှာ သိမ်းဆည်းထားပါတယ်။ အဲဒီ Controller ဖိုင်တွေကို `Composer.json` မှာ `Classmap စနစ်ဖြင့်အသုံးပြုထားပါတယ်။ဘယ်လိုပဲဖြစ်ဖြစ် Controllers တွေက Application ရဲ့ ဘယ်နေရာမှာ မဆို အလုပ်လုပ်နိုင်ပါတယ်။ Route မှာ Controllers ကို သိမ်းဆန်းထားတဲ့နေရာအတွက် သတ်မှတ်ချက်တွေက မရှိပါ။ဘာလို့လဲဆိုတော့ Composer က Classmap autoload သုံးပြုထားတဲ့ controller class ကို အလိုလို သိမှတ်ပြုပြီးသားဖြစ်နေလို့ပါ။Controllers ဖိုင်တွေကို နှစ်သက်ရာ နေရာမှာ သိမ်းဆည်းပြီး အလုပ်လုပ်နိုင်ပါတယ်။ +Below is an example of a basic controller class. Note that the controller extends the base controller class included with Laravel. The base class provides a few convenience methods such as the `middleware` method, which may be used to attach middleware to controller actions: -အခြေခံအားဖြင့် Controller Class တခုရဲ့ ပုံစံက အောက်ပါအတိုင်းရေးသားပါတယ်။ + $user)); - } + class UserController extends Controller + { + /** + * Show the profile for the given user. + * + * @param int $id + * @return Response + */ + public function show($id) + { + return view('user.profile', ['user' => User::findOrFail($id)]); + } + } - } +You can define a route to this controller action like so: + Route::get('user/{id}', 'UserController@show'); -Controllers တွေအားလုံးက `BaseController` Class ကို ထပ်ကွန့် အသုံးပြုရမှာပါ။ `BaseController` ကိုလဲ `app/controllers` မှာ သိမ်းဆည်းထားပြီး ပြန်လည်အသုံးပြုနိုင်တဲ့ ဖိုင်အနေနဲ့သိမ်းဆည်းထားပါတယ်။`BaseContoller` ဆိုတာက Laravel framework ရဲ့ `Controller` Class ကို ထပ်ကွန့် အသုံးပြုထားပါတယ်။အခုဆိုရင်တော့ Route ဖိုင်မှ တဆင့် အသုံးပြုလိုတဲ့ Controller action ကို အောက်ပါအတိုင်းသတ်မှတ်နိုင်ပါပြီ။ +Now, when a request matches the specified route URI, the `show` method on the `UserController` class will be executed. Of course, the route parameters will also be passed to the method. - Route::get('user/{id}', 'UserController@showProfile'); +> {tip} Controllers are not **required** to extend a base class. However, you will not have access to convenience features such as the `middleware`, `validate`, and `dispatch` methods. + +### Controllers & Namespaces -PHP ရဲ့ magic function namespaces ကို အသုံးပြုပြီး Controller ကို သတ်မှတ်မယ်ဆိုရင်တော့ အောက်ကပုံစံအတိုင်း Route ပေးတဲ့အချိန်မှာ သတ်မှတ်နိုင်ပါတယ်။ +It is very important to note that we did not need to specify the full controller namespace when defining the controller route. Since the `RouteServiceProvider` loads your route files within a route group that contains the namespace, we only specified the portion of the class name that comes after the `App\Http\Controllers` portion of the namespace. - Route::get('foo', 'Namespace\FooController@method'); +If you choose to nest your controllers deeper into the `App\Http\Controllers` directory, simply use the specific class name relative to the `App\Http\Controllers` root namespace. So, if your full controller class is `App\Http\Controllers\Photos\AdminController`, you should register routes to the controller like so: -> **Note::** အခုချိန်မှာ ကျွန်တော်တို့က PHP classes တွေ ကို autoload အသုံးပြုနိုင်ရန်အတွက် [Composer](http://getcomposer.org) ကို အသုံးပြုထားပါတယ်။ ဒါကြောင့် Controller file ကို System ရဲ့ ဘယ်နေရာမှာပဲထားထား ၊ Composer က အဲဒီ ဖိုင်ကို သိနေသ၍ အသုံးပြုနိုင်မှာပါ။ Controllers ဖိုင်ရဲ့ တည်နေရာကို အတည်တကျ အသေ သတ်မှတ်ထားသလိုမျိုးမရှိပါဘူး။Routing to controllers is entirely de-coupled from the file system. + Route::get('foo', 'Photos\AdminController@method'); + +### Single Action Controllers -Controller ကို သတ်မှတ်ထားတဲ့ Route ကို အောက်ကပုံစံအတိုင်း သတ်မှတ်နိုင်ပါတယ်။ +If you would like to define a controller that only handles a single action, you may place a single `__invoke` method on the controller: - Route::get('foo', array('uses' => 'FooController@method','as' => 'name')); + User::findOrFail($id)]); + } + } -Controller action တစ်ခုရဲ့ နာမည်ကို သိရန်အတွက် 'currentRouteAction' method ကို အောက်က ပုံစံအတိုင်း အသုံးပြုနိုင်ပါတယ်။ +When registering routes for single action controllers, you do not need to specify a method: - $action = Route::currentRouteAction(); + Route::get('user/{id}', 'ShowProfile'); - -## Controller Filters + +## Controller Middleware -[Filters](routing#route-filters.md) က Controller ပါတဲ့ route တခုသတ်မှတ်ကတည်းက အောက်ပါပုံစံအတိုင်း သတ်မှတ်ခဲ့ပါတယ်။ +[Middleware](/docs/{{version}}/middleware) may be assigned to the controller's routes in your route files: - Route::get('profile', array('before' => 'auth', - 'uses' => 'UserController@showProfile')); + Route::get('profile', 'UserController@show')->middleware('auth'); -နောက်တစ်နည်းက Controller ဖိုင်ထဲရောက်မှ အောက်ကပုံစံအတိုင်းလဲ အသုံးပြုနိုင်ပါတယ်။ +However, it is more convenient to specify middleware within your controller's constructor. Using the `middleware` method from your controller's constructor, you may easily assign middleware to the controller's action. You may even restrict the middleware to only certain methods on the controller class: - class UserController extends BaseController { + class UserController extends Controller + { + /** + * Instantiate a new controller instance. + * + * @return void + */ + public function __construct() + { + $this->middleware('auth'); - /** - * Instantiate a new UserController instance. - */ - public function __construct() - { - $this->beforeFilter('auth', array('except' => 'getLogin')); + $this->middleware('log')->only('index'); - $this->beforeFilter('csrf', array('on' => 'post')); + $this->middleware('subscribed')->except('store'); + } + } - $this->afterFilter('log', array('only' => - array('fooAction', 'barAction'))); - } +Controllers also allow you to register middleware using a Closure. This provides a convenient way to define a middleware for a single controller without defining an entire middleware class: - } + $this->middleware(function ($request, $next) { + // ... + return $next($request); + }); -You may also specify controller filters inline using a Closure: +> {tip} You may assign middleware to a subset of controller actions; however, it may indicate your controller is growing too large. Instead, consider breaking your controller into multiple, smaller controllers. - class UserController extends BaseController { + +## Resource Controllers - /** - * Instantiate a new UserController instance. - */ - public function __construct() - { - $this->beforeFilter(function() - { - // - }); - } +Laravel resource routing assigns the typical "CRUD" routes to a controller with a single line of code. For example, you may wish to create a controller that handles all HTTP requests for "photos" stored by your application. Using the `make:controller` Artisan command, we can quickly create such a controller: - } + php artisan make:controller PhotoController --resource -Controller တစ်ခုအတွက် Filter ကို သီးခြားအသုံးပြုချင်ရင်တော့ `@` ဆိုတဲ့ syntax ကို အသုံးပြုပြီး အောက်ပါအတိုင်း သတ်မှတ်ပေးရပါတယ်။ +This command will generate a controller at `app/Http/Controllers/PhotoController.php`. The controller will contain a method for each of the available resource operations. - class UserController extends BaseController { +Next, you may register a resourceful route to the controller: - /** - * Instantiate a new UserController instance. - */ - public function __construct() - { - $this->beforeFilter('@filterRequests'); - } + Route::resource('photos', 'PhotoController'); - /** - * Filter the incoming requests. - */ - public function filterRequests($route, $request) - { - // - } +This single route declaration creates multiple routes to handle a variety of actions on the resource. The generated controller will already have methods stubbed for each of these actions, including notes informing you of the HTTP verbs and URIs they handle. - } +#### Actions Handled By Resource Controller - +Verb | URI | Action | Route Name +----------|-----------------------|--------------|--------------------- +GET | `/photos` | index | photos.index +GET | `/photos/create` | create | photos.create +POST | `/photos` | store | photos.store +GET | `/photos/{photo}` | show | photos.show +GET | `/photos/{photo}/edit` | edit | photos.edit +PUT/PATCH | `/photos/{photo}` | update | photos.update +DELETE | `/photos/{photo}` | destroy | photos.destroy -## RESTful Controllers +#### Specifying The Resource Model -Laravel တွင် Controller တွေရဲ့ Action အားလုံးအတွက် REST ဖြင့် Route ကနေ အလွယ်တကူ သတ်မှတ်နိုင်ပါတယ်။ ပထမဆုံး method အတွက် Route ကို 'Route::controller' ဖြင့် သတ်မှတ်ပါ။ +If you are using route model binding and would like the resource controller's methods to type-hint a model instance, you may use the `--model` option when generating the controller: - Route::controller('users', 'UserController'); + php artisan make:controller PhotoController --resource --model=Photo -`controller` method တွင် arguments နှစ်ခု လက်ခံပါတယ်။ ပထမတခုက Base URL controller handles( ဥပမာ. create, index ) ဖြစ်ပြီး ၊ ဒုတိယတခုကတော့ Controller ရဲ့ နာမည်ဖြစ်ပါတယ်။ နောက်တစ်ခုက Controller တွင် Method(getindex/postprofile)တွေကို HTTP verb အလိုက် ထည့်ပေးရပါမယ်။ +#### Spoofing Form Methods - class UserController extends BaseController { +Since HTML forms can't make `PUT`, `PATCH`, or `DELETE` requests, you will need to add a hidden `_method` field to spoof these HTTP verbs. The `method_field` helper can create this field for you: - public function getIndex() - { - // - } + {{ method_field('PUT') }} - public function postProfile() - { - // - } + +### Partial Resource Routes - } +When declaring a resource route, you may specify a subset of actions the controller should handle instead of the full set of default actions: -`index` method က route မှာပေးထားတဲ့ index ကို အလုပ်လုပ်ပါတယ်။ ကျွန်တော်တို့ အပေါ်မှာဆို route name ကို users ဆိုပြီးပေးခဲ့ပါတယ်။ အဲဒါဆိုရင် users လို့ခေါ်ရင် Controller ထဲက index က အလုပ်လုပ်သွားမှာပါ။ + Route::resource('photo', 'PhotoController', ['only' => [ + 'index', 'show' + ]]); -Controller action မှာ စကားစုအများကြီးပါလာသုံးခဲ့ရင် `dash` syntax သုံးနည်းနဲ့ Mathod ကို သတ်မှတ်ပေးရပါတယ်။ ဥပမာ "OurController" ထဲက method တစ်ခု ကို getAdminProfile လို့ပေးထားရင် url ကို `users/admin-profile` လို့ခေါ်လို့ရသွားမှာပါ။ + Route::resource('photo', 'PhotoController', ['except' => [ + 'create', 'store', 'update', 'destroy' + ]]); - public function getAdminProfile() {} + +### Naming Resource Routes - -## Resource Controllers +By default, all resource controller actions have a route name; however, you can override these names by passing a `names` array with your options: -Resource controllers က sources တွေ အသုံးပြုပြီး Restful controller တွေ ဖန်တီးတဲ့အခါ အလွယ်တကူအသုံးပြုနိုင်အောင်လုပ်ဆောင်ပေးပါတယ်။ ဥပမာ ဓါတ်ပုံ စီမံတဲ့ controller တစ်တခု ပြုလုပ်မယ်ဆိုပါစို ့။ Terminal(CMD) ကနေ တစ်ဆင့် Artisan command ဖြင့် `controller:make` ကိုအသုံးပြုပြီးတော့ `Route::resource` ဆိုပြီး route သတ်မှတ်ပေးလိုက်ရင် resoure controller တစ်ခု အလွယ်တကူရရှိမှာဖြစ်ပါတယ်။ + Route::resource('photo', 'PhotoController', ['names' => [ + 'create' => 'photo.build' + ]]); -Controller တစ်ခုကို Terminal(cmd) ကနေ ဖန်တီးဖို့အတွက် အောက်က ကွန်မန်းဖြင့် စမ်းကြည့်ပါ။ + +### Naming Resource Route Parameters - php artisan controller:make PhotoController +By default, `Route::resource` will create the route parameters for your resource routes based on the "singularized" version of the resource name. You can easily override this on a per resource basis by passing `parameters` in the options array. The `parameters` array should be an associative array of resource names and parameter names: -ပြီးရင်တော့ အပေါ်မှာ လုပ်ထားတဲ့ Controller ကို အသုံးပြုနိုင်ရန်အတွက်အောက်ကအတိုင်း Route မှာ သတ်မှတ်ပေးပါ။ + Route::resource('user', 'AdminUserController', ['parameters' => [ + 'user' => 'admin_user' + ]]); - Route::resource('photo', 'PhotoController'); + The example above generates the following URIs for the resource's `show` route: + /user/{admin_user} -အခုဆိုရင် သာမန် Route လေးတစ်ကြောင်းနဲ့ Photo အတွက် RESTful action တစ်ခုရရှိသွားပါပြီ။အခုလိုမျိုးသတ်မှတ်ရုံဖြင့် အောက်ကအတိုင်း Action တွေ အကုန်အသုံးပြုနိုင်သွားပါပြီ။ + +### Supplementing Resource Controllers -#### Actions Handled By Resource Controller +If you need to add additional routes to a resource controller beyond the default set of resource routes, you should define those routes before your call to `Route::resource`; otherwise, the routes defined by the `resource` method may unintentionally take precedence over your supplemental routes: + + Route::get('photos/popular', 'PhotoController@method'); + + Route::resource('photos', 'PhotoController'); + +> {tip} Remember to keep your controllers focused. If you find yourself routinely needing methods outside of the typical set of resource actions, consider splitting your controller into two, smaller controllers. + + +## Dependency Injection & Controllers + +#### Constructor Injection + +The Laravel [service container](/docs/{{version}}/container) is used to resolve all Laravel controllers. As a result, you are able to type-hint any dependencies your controller may need in its constructor. The declared dependencies will automatically be resolved and injected into the controller instance: + + users = $users; + } + } + +Of course, you may also type-hint any [Laravel contract](/docs/{{version}}/contracts). If the container can resolve it, you can type-hint it. Depending on your application, injecting your dependencies into your controller may provide better testability. + +#### Method Injection + +In addition to constructor injection, you may also type-hint dependencies on your controller's methods. A common use-case for method injection is injecting the `Illuminate\Http\Request` instance into your controller methods: -Verb | Path | Action | Route Name -----------|-----------------------------|--------------|--------------------- -GET | /resource | index | resource.index -GET | /resource/create | create | resource.create -POST | /resource | store | resource.store -GET | /resource/{resource} | show | resource.show -GET | /resource/{resource}/edit | edit | resource.edit -PUT/PATCH | /resource/{resource} | update | resource.update -DELETE | /resource/{resource} | destroy | resource.destroy + name; + // + } + } -ပြီးတော့ Route မှ တဆင့်လဲ လိုအပ်တဲ့ Action တွေ ကို only ကို အသုံးပြုပြီး သတ်မှတ်ပေးသွားနိုင်ပါတယ်။ +If your controller method is also expecting input from a route parameter, simply list your route arguments after your other dependencies. For example, if your route is defined like so: - Route::resource('photo', 'PhotoController', - array('only' => array('index', 'show'))); + Route::put('user/{id}', 'UserController@update'); - Route::resource('photo', 'PhotoController', - array('except' => array('create', 'store', 'update', 'destroy'))); +You may still type-hint the `Illuminate\Http\Request` and access your `id` parameter by defining your controller method as follows: -ပုံမှန်အားဖြင့် Resource controller action တွေမှာ route name တွေက အလိုလျောက်သတ်မှတ်ပေးထားပြီးသားပါ။တကယ်လို ့ အဲဒီ route name ကို ကိုယ့်ဘာသာ အောက်က ပုံစံအတိုင်း သတ်မှတ်ပေးလို့ရနိုင်ပါသေးတယ်။ + array('create' => 'photo.build'))); + namespace App\Http\Controllers; -#### Adding Additional Routes To Resource Controllers + use Illuminate\Http\Request; -တကယ်လို့ resource controller မှာ ပုံမှန် routes တွေနဲ့ မလုံလောက်လို့ အသစ်ထပ်ထည့်လို့ရနိုင်ပါသေးတယ်။ အဲဒီ route name ကိုတော့ `Route::resource` ကို မရေးခင်မှာအောက်က ပုံစံအတိုင်း ရေးပေးရပါမယ်။ + class UserController extends Controller + { + /** + * Update the given user. + * + * @param Request $request + * @param string $id + * @return Response + */ + public function update(Request $request, $id) + { + // + } + } - Route::get('photos/popular'); - Route::resource('photos', 'PhotoController'); + +## Route Caching - -## Handling Missing Methods +> {note} Closure based routes cannot be cached. To use route caching, you must convert any Closure routes to controller classes. -"catch-all method" ဆိုတာက Controller ပေးထားပြီး Mehod မရှိတဲ့အခါမှာ အလုပ်လုပ်မယ့် အခြေအနေဖြစ်ပါတယ်။ Method နာမည်ကိုတော့ "MissingMethod" ဆိုပြီးအောက်ကပုံစံအတိုင်း အသုံးပြုရမှာပါ။ +If your application is exclusively using controller based routes, you should take advantage of Laravel's route cache. Using the route cache will drastically decrease the amount of time it takes to register all of your application's routes. In some cases, your route registration may even be up to 100x faster. To generate a route cache, just execute the `route:cache` Artisan command: -#### Defining A Catch-All Method + php artisan route:cache - public function missingMethod($parameters = array()) - { - // - } +After running this command, your cached routes file will be loaded on every request. Remember, if you add any new routes you will need to generate a fresh route cache. Because of this, you should only run the `route:cache` command during your project's deployment. +You may use the `route:clear` command to clear the route cache: - [1]: /docs/ioc \ No newline at end of file + php artisan route:clear diff --git a/csrf.md b/csrf.md new file mode 100644 index 0000000..7533ffc --- /dev/null +++ b/csrf.md @@ -0,0 +1,69 @@ +# CSRF Protection + +- [Introduction](#csrf-introduction) +- [Excluding URIs](#csrf-excluding-uris) +- [X-CSRF-Token](#csrf-x-csrf-token) +- [X-XSRF-Token](#csrf-x-xsrf-token) + + +## Introduction + +Laravel makes it easy to protect your application from [cross-site request forgery](https://en.wikipedia.org/wiki/Cross-site_request_forgery) (CSRF) attacks. Cross-site request forgeries are a type of malicious exploit whereby unauthorized commands are performed on behalf of an authenticated user. + +Laravel automatically generates a CSRF "token" for each active user session managed by the application. This token is used to verify that the authenticated user is the one actually making the requests to the application. + +Anytime you define a HTML form in your application, you should include a hidden CSRF token field in the form so that the CSRF protection middleware can validate the request. You may use the `csrf_field` helper to generate the token field: + +
    + {{ csrf_field() }} + ... +
    + +The `VerifyCsrfToken` [middleware](/docs/{{version}}/middleware), which is included in the `web` middleware group, will automatically verify that the token in the request input matches the token stored in the session. + + +## Excluding URIs From CSRF Protection + +Sometimes you may wish to exclude a set of URIs from CSRF protection. For example, if you are using [Stripe](https://stripe.com) to process payments and are utilizing their webhook system, you will need to exclude your Stripe webhook handler route from CSRF protection since Stripe will not know what CSRF token to send to your routes. + +Typically, you should place these kinds of routes outside of the `web` middleware group that the `RouteServiceProvider` applies to all routes in the `routes/web.php` file. However, you may also exclude the routes by adding their URIs to the `$except` property of the `VerifyCsrfToken` middleware: + + +## X-CSRF-TOKEN + +In addition to checking for the CSRF token as a POST parameter, the `VerifyCsrfToken` middleware will also check for the `X-CSRF-TOKEN` request header. You could, for example, store the token in a HTML `meta` tag: + + + +Then, once you have created the `meta` tag, you can instruct a library like jQuery to automatically add the token to all request headers. This provides simple, convenient CSRF protection for your AJAX based applications: + + $.ajaxSetup({ + headers: { + 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') + } + }); + + +## X-XSRF-TOKEN + +Laravel stores the current CSRF token in a `XSRF-TOKEN` cookie that is included with each response generated by the framework. You can use the cookie value to set the `X-XSRF-TOKEN` request header. + +This cookie is primarily sent as a convenience since some JavaScript frameworks, like Angular, automatically place its value in the `X-XSRF-TOKEN` header. diff --git a/database-testing.md b/database-testing.md new file mode 100644 index 0000000..36f10e8 --- /dev/null +++ b/database-testing.md @@ -0,0 +1,226 @@ +# Database Testing + +- [Introduction](#introduction) +- [Resetting The Database After Each Test](#resetting-the-database-after-each-test) + - [Using Migrations](#using-migrations) + - [Using Transactions](#using-transactions) +- [Writing Factories](#writing-factories) + - [Factory States](#factory-states) +- [Using Factories](#using-factories) + - [Creating Models](#creating-models) + - [Persisting Models](#persisting-models) + - [Relationships](#relationships) + + +## Introduction + +Laravel provides a variety of helpful tools to make it easier to test your database driven applications. First, you may use the `assertDatabaseHas` helper to assert that data exists in the database matching a given set of criteria. For example, if you would like to verify that there is a record in the `users` table with the `email` value of `sally@example.com`, you can do the following: + + public function testDatabase() + { + // Make call to application... + + $this->assertDatabaseHas('users', [ + 'email' => 'sally@example.com' + ]); + } + +Of course, the `assertDatabaseHas` method and other helpers like it are for convenience. You are free to use any of PHPUnit's built-in assertion methods to supplement your tests. + + +## Resetting The Database After Each Test + +It is often useful to reset your database after each test so that data from a previous test does not interfere with subsequent tests. + + +### Using Migrations + +One approach to resetting the database state is to rollback the database after each test and migrate it before the next test. Laravel provides a simple `DatabaseMigrations` trait that will automatically handle this for you. Simply use the trait on your test class and everything will be handled for you: + + get('/'); + + // ... + } + } + + +### Using Transactions + +Another approach to resetting the database state is to wrap each test case in a database transaction. Again, Laravel provides a convenient `DatabaseTransactions` trait that will automatically handle this for you: + + get('/'); + + // ... + } + } + +> {note} By default, this trait will only wrap the default database connection in a transaction. If your application is using multiple database connections, you should define a `$connectionsToTransact` property on your test class. This property should be an array of connection names to execute the transactions on. + + +## Writing Factories + +When testing, you may need to insert a few records into your database before executing your test. Instead of manually specifying the value of each column when you create this test data, Laravel allows you to define a default set of attributes for each of your [Eloquent models](/docs/{{version}}/eloquent) using model factories. To get started, take a look at the `database/factories/ModelFactory.php` file in your application. Out of the box, this file contains one factory definition: + + $factory->define(App\User::class, function (Faker\Generator $faker) { + static $password; + + return [ + 'name' => $faker->name, + 'email' => $faker->unique()->safeEmail, + 'password' => $password ?: $password = bcrypt('secret'), + 'remember_token' => str_random(10), + ]; + }); + +Within the Closure, which serves as the factory definition, you may return the default test values of all attributes on the model. The Closure will receive an instance of the [Faker](https://github.com/fzaninotto/Faker) PHP library, which allows you to conveniently generate various kinds of random data for testing. + +Of course, you are free to add your own additional factories to the `ModelFactory.php` file. You may also create additional factory files for each model for better organization. For example, you could create `UserFactory.php` and `CommentFactory.php` files within your `database/factories` directory. All of the files within the `factories` directory will automatically be loaded by Laravel. + + +### Factory States + +States allow you to define discrete modifications that can be applied to your model factories in any combination. For example, your `User` model might have a `delinquent` state that modifies one of its default attribute values. You may define your state transformations using the `state` method: + + $factory->state(App\User::class, 'delinquent', function ($faker) { + return [ + 'account_status' => 'delinquent', + ]; + }); + + +## Using Factories + + +### Creating Models + +Once you have defined your factories, you may use the global `factory` function in your tests or seed files to generate model instances. So, let's take a look at a few examples of creating models. First, we'll use the `make` method to create models but not save them to the database: + + public function testDatabase() + { + $user = factory(App\User::class)->make(); + + // Use model in tests... + } + +You may also create a Collection of many models or create models of a given type: + + // Create three App\User instances... + $users = factory(App\User::class, 3)->make(); + +#### Applying States + +You may also apply any of your [states](#factory-states) to the models. If you would like to apply multiple state transformations to the models, you should specify the name of each state you would like to apply: + + $users = factory(App\User::class, 5)->states('delinquent')->make(); + + $users = factory(App\User::class, 5)->states('premium', 'delinquent')->make(); + +#### Overriding Attributes + +If you would like to override some of the default values of your models, you may pass an array of values to the `make` method. Only the specified values will be replaced while the rest of the values remain set to their default values as specified by the factory: + + $user = factory(App\User::class)->make([ + 'name' => 'Abigail', + ]); + + +### Persisting Models + +The `create` method not only creates the model instances but also saves them to the database using Eloquent's `save` method: + + public function testDatabase() + { + // Create a single App\User instance... + $user = factory(App\User::class)->create(); + + // Create three App\User instances... + $users = factory(App\User::class, 3)->create(); + + // Use model in tests... + } + +You may override attributes on the model by passing an array to the `create` method: + + $user = factory(App\User::class)->create([ + 'name' => 'Abigail', + ]); + + +### Relationships + +In this example, we'll attach a relation to some created models. When using the `create` method to create multiple models, an Eloquent [collection instance](/docs/{{version}}/eloquent-collections) is returned, allowing you to use any of the convenient functions provided by the collection, such as `each`: + + $users = factory(App\User::class, 3) + ->create() + ->each(function ($u) { + $u->posts()->save(factory(App\Post::class)->make()); + }); + +#### Relations & Attribute Closures + +You may also attach relationships to models using Closure attributes in your factory definitions. For example, if you would like to create a new `User` instance when creating a `Post`, you may do the following: + + $factory->define(App\Post::class, function ($faker) { + return [ + 'title' => $faker->title, + 'content' => $faker->paragraph, + 'user_id' => function () { + return factory(App\User::class)->create()->id; + } + ]; + }); + +These Closures also receive the evaluated attribute array of the factory that defines them: + + $factory->define(App\Post::class, function ($faker) { + return [ + 'title' => $faker->title, + 'content' => $faker->paragraph, + 'user_id' => function () { + return factory(App\User::class)->create()->id; + }, + 'user_type' => function (array $post) { + return App\User::find($post['user_id'])->type; + } + ]; + }); diff --git a/database.md b/database.md index 82805c1..3090a0f 100644 --- a/database.md +++ b/database.md @@ -1,134 +1,232 @@ -# Basic Database Usage - -- [Configuration](#configuration) -- [Read / Write Connections](#read-write-connections) -- [Running Queries](#running-queries) +# Database: Getting Started + +- [Introduction](#introduction) + - [Configuration](#configuration) + - [Read & Write Connections](#read-and-write-connections) + - [Using Multiple Database Connections](#using-multiple-database-connections) +- [Running Raw SQL Queries](#running-queries) + - [Listening For Query Events](#listening-for-query-events) - [Database Transactions](#database-transactions) -- [Accessing Connections](#accessing-connections) -- [Query Logging](#query-logging) + + +## Introduction + +Laravel makes interacting with databases extremely simple across a variety of database backends using either raw SQL, the [fluent query builder](/docs/{{version}}/queries), and the [Eloquent ORM](/docs/{{version}}/eloquent). Currently, Laravel supports four databases: + +
    +- MySQL +- Postgres +- SQLite +- SQL Server +
    -## Configuration +### Configuration + +The database configuration for your application is located at `config/database.php`. In this file you may define all of your database connections, as well as specify which connection should be used by default. Examples for most of the supported database systems are provided in this file. + +By default, Laravel's sample [environment configuration](/docs/{{version}}/configuration#environment-configuration) is ready to use with [Laravel Homestead](/docs/{{version}}/homestead), which is a convenient virtual machine for doing Laravel development on your local machine. Of course, you are free to modify this configuration as needed for your local database. + +#### SQLite Configuration + +After creating a new SQLite database using a command such as `touch database/database.sqlite`, you can easily configure your environment variables to point to this newly created database by using the database's absolute path: -Laravel makes connecting with databases and running queries extremely simple. The database configuration file is `app/config/database.php`. In this file you may define all of your database connections, as well as specify which connection should be used by default. Examples for all of the supported database systems are provided in this file. + DB_CONNECTION=sqlite + DB_DATABASE=/absolute/path/to/database.sqlite -Currently Laravel supports four database systems: MySQL, Postgres, SQLite, and SQL Server. +#### SQL Server Configuration - -## Read / Write Connections +Laravel supports SQL Server out of the box; however, you will need to add the connection configuration for the database to your `config/database.php` configuration file: + + 'sqlsrv' => [ + 'driver' => 'sqlsrv', + 'host' => env('DB_HOST', 'localhost'), + 'database' => env('DB_DATABASE', 'forge'), + 'username' => env('DB_USERNAME', 'forge'), + 'password' => env('DB_PASSWORD', ''), + 'charset' => 'utf8', + 'prefix' => '', + ], + + +### Read & Write Connections Sometimes you may wish to use one database connection for SELECT statements, and another for INSERT, UPDATE, and DELETE statements. Laravel makes this a breeze, and the proper connections will always be used whether you are using raw queries, the query builder, or the Eloquent ORM. To see how read / write connections should be configured, let's look at this example: - 'mysql' => array( - 'read' => array( - 'host' => '192.168.1.1', - ), - 'write' => array( - 'host' => '196.168.1.2' - ), - 'driver' => 'mysql', - 'database' => 'database', - 'username' => 'root', - 'password' => '', - 'charset' => 'utf8', - 'collation' => 'utf8_unicode_ci', - 'prefix' => '', - ), - -Note that two keys have been added to the configuration array: `read` and `write`. Both of these keys have array values containing a single key: `host`. The rest of the database options for the `read` and `write` connections will be merged from the main `mysql` array. So, we only need to place items in the `read` and `write` arrays if we wish to override the values in the main array. So, in this case, `192.168.1.1` will be used as the "read" connection, while `192.168.1.2` will be used as the "write" connection. The database credentials, prefix, character set, and all other options in the main `mysql` array will be shared across both connections. + 'mysql' => [ + 'read' => [ + 'host' => '192.168.1.1', + ], + 'write' => [ + 'host' => '196.168.1.2' + ], + 'driver' => 'mysql', + 'database' => 'database', + 'username' => 'root', + 'password' => '', + 'charset' => 'utf8', + 'collation' => 'utf8_unicode_ci', + 'prefix' => '', + ], + +Note that two keys have been added to the configuration array: `read` and `write`. Both of these keys have array values containing a single key: `host`. The rest of the database options for the `read` and `write` connections will be merged from the main `mysql` array. + +You only need to place items in the `read` and `write` arrays if you wish to override the values from the main array. So, in this case, `192.168.1.1` will be used as the host for the "read" connection, while `192.168.1.2` will be used for the "write" connection. The database credentials, prefix, character set, and all other options in the main `mysql` array will be shared across both connections. + + +### Using Multiple Database Connections + +When using multiple connections, you may access each connection via the `connection` method on the `DB` facade. The `name` passed to the `connection` method should correspond to one of the connections listed in your `config/database.php` configuration file: + + $users = DB::connection('foo')->select(...); + +You may also access the raw, underlying PDO instance using the `getPdo` method on a connection instance: + + $pdo = DB::connection()->getPdo(); -## Running Queries +## Running Raw SQL Queries -Once you have configured your database connection, you may run queries using the `DB` class. +Once you have configured your database connection, you may run queries using the `DB` facade. The `DB` facade provides methods for each type of query: `select`, `update`, `insert`, `delete`, and `statement`. #### Running A Select Query - $results = DB::select('select * from users where id = ?', array(1)); +To run a basic query, you may use the `select` method on the `DB` facade: -The `select` method will always return an `array` of results. + $users]); + } + } -#### Running A Delete Statement +The first argument passed to the `select` method is the raw SQL query, while the second argument is any parameter bindings that need to be bound to the query. Typically, these are the values of the `where` clause constraints. Parameter binding provides protection against SQL injection. - DB::delete('delete from users'); +The `select` method will always return an `array` of results. Each result within the array will be a PHP `StdClass` object, allowing you to access the values of the results: -> **Note:** The `update` and `delete` statements return the number of rows affected by the operation. + foreach ($users as $user) { + echo $user->name; + } -#### Running A General Statement +#### Using Named Bindings - DB::statement('drop table users'); +Instead of using `?` to represent your parameter bindings, you may execute a query using named bindings: -#### Listening For Query Events + $results = DB::select('select * from users where id = :id', ['id' => 1]); -You may listen for query events using the `DB::listen` method: +#### Running An Insert Statement - DB::listen(function($sql, $bindings, $time) - { - // - }); +To execute an `insert` statement, you may use the `insert` method on the `DB` facade. Like `select`, this method takes the raw SQL query as its first argument and bindings as its second argument: - -## Database Transactions + DB::insert('insert into users (id, name) values (?, ?)', [1, 'Dayle']); -To run a set of operations within a database transaction, you may use the `transaction` method: +#### Running An Update Statement - DB::transaction(function() - { - DB::table('users')->update(array('votes' => 1)); +The `update` method should be used to update existing records in the database. The number of rows affected by the statement will be returned: - DB::table('posts')->delete(); - }); + $affected = DB::update('update users set votes = 100 where name = ?', ['John']); -> **Note:** Any exception thrown within the `transaction` closure will cause the transaction to be rolled back automatically. +#### Running A Delete Statement -Sometimes you may need to begin a transaction yourself: +The `delete` method should be used to delete records from the database. Like `update`, the number of rows affected will be returned: - DB::beginTransaction(); + $deleted = DB::delete('delete from users'); -You can rollback a transaction via the `rollback` method: +#### Running A General Statement - DB::rollback(); +Some database statements do not return any value. For these types of operations, you may use the `statement` method on the `DB` facade: + + DB::statement('drop table users'); + + +### Listening For Query Events + +If you would like to receive each SQL query executed by your application, you may use the `listen` method. This method is useful for logging queries or debugging. You may register your query listener in a [service provider](/docs/{{version}}/providers): + + sql + // $query->bindings + // $query->time + }); + } + + /** + * Register the service provider. + * + * @return void + */ + public function register() + { + // + } + } -Lastly, you can commit a transaction via the `commit` method: + +## Database Transactions - DB::commit(); +You may use the `transaction` method on the `DB` facade to run a set of operations within a database transaction. If an exception is thrown within the transaction `Closure`, the transaction will automatically be rolled back. If the `Closure` executes successfully, the transaction will automatically be committed. You don't need to worry about manually rolling back or committing while using the `transaction` method: - -## Accessing Connections + DB::transaction(function () { + DB::table('users')->update(['votes' => 1]); -When using multiple connections, you may access them via the `DB::connection` method: + DB::table('posts')->delete(); + }); - $users = DB::connection('foo')->select(...); +#### Handling Deadlocks -You may also access the raw, underlying PDO instance: +The `transaction` method accepts an optional second argument which defines the number of times a transaction should be reattempted when a deadlock occurs. Once these attempts have been exhausted, an exception will be thrown: - $pdo = DB::connection()->getPdo(); + DB::transaction(function () { + DB::table('users')->update(['votes' => 1]); -Sometimes you may need to reconnect to a given database: + DB::table('posts')->delete(); + }, 5); - DB::reconnect('foo'); +#### Manually Using Transactions -If you need to disconnect from the given database due to exceeding the underlying PDO instance's `max_connections` limit, use the `disconnect` method: +If you would like to begin a transaction manually and have complete control over rollbacks and commits, you may use the `beginTransaction` method on the `DB` facade: - DB::disconnect('foo'); + DB::beginTransaction(); - -## Query Logging +You can rollback the transaction via the `rollBack` method: -By default, Laravel keeps a log in memory of all queries that have been run for the current request. However, in some cases, such as when inserting a large number of rows, this can cause the application to use excess memory. To disable the log, you may use the `disableQueryLog` method: + DB::rollBack(); - DB::connection()->disableQueryLog(); +Lastly, you can commit a transaction via the `commit` method: -To get an array of the executed queries, you may use the `getQueryLog` method: + DB::commit(); - $queries = DB::getQueryLog(); +> {tip} Using the `DB` facade's transaction methods also controls transactions for the [query builder](/docs/{{version}}/queries) and [Eloquent ORM](/docs/{{version}}/eloquent). diff --git a/documentation.md b/documentation.md index fb79572..ab11db8 100644 --- a/documentation.md +++ b/documentation.md @@ -1,46 +1,79 @@ -- Preface - - [Introduction](introduction.md) - - [Quickstart](quick.md) - - [Release Notes](releases.md) - - [Upgrade Guide](upgrade.md) +- Prologue + - [Release Notes](/docs/{{version}}/releases) + - [Upgrade Guide](/docs/{{version}}/upgrade) + - [Contribution Guide](/docs/{{version}}/contributions) + - [API Documentation](/api/{{version}}) - Getting Started - - [Installation](installation.md) - - [Configuration](configuration.md) - - [Homestead](homestead.md) - - [Request Lifecycle](lifecycle.md) - - [Routing](routing.md) - - [Requests & Input](requests.md) - - [Views & Responses](responses.md) - - [Controllers](controllers.md) - - [Errors & Logging](errors.md) -- Learning More - - [Authentication](security.md) - - [Billing](billing.md) - - [Cache](cache.md) - - [Core Extension](extending.md) - - [Events](events.md) - - [Facades](facades.md) - - [Forms & HTML](html.md) - - [Helpers](helpers.md) - - [IoC Container](ioc.md) - - [Localization](localization.md) - - [Mail](mail.md) - - [Package Development](packages.md) - - [Pagination](pagination.md) - - [Queues](queues.md) - - [Security](security.md) - - [Session](session.md) - - [SSH](ssh.md) - - [Templates](templates.md) - - [Unit Testing](testing.md) - - [Validation](validation.md) + - [Installation](/docs/{{version}}/installation) + - [Configuration](/docs/{{version}}/configuration) + - [Directory Structure](/docs/{{version}}/structure) + - [Request Lifecycle](/docs/{{version}}/lifecycle) +- Dev Environments + - [Homestead](/docs/{{version}}/homestead) + - [Valet](/docs/{{version}}/valet) +- Core Concepts + - [Service Container](/docs/{{version}}/container) + - [Service Providers](/docs/{{version}}/providers) + - [Facades](/docs/{{version}}/facades) + - [Contracts](/docs/{{version}}/contracts) +- The HTTP Layer + - [Routing](/docs/{{version}}/routing) + - [Middleware](/docs/{{version}}/middleware) + - [CSRF Protection](/docs/{{version}}/csrf) + - [Controllers](/docs/{{version}}/controllers) + - [Requests](/docs/{{version}}/requests) + - [Responses](/docs/{{version}}/responses) + - [Views](/docs/{{version}}/views) + - [Session](/docs/{{version}}/session) + - [Validation](/docs/{{version}}/validation) +- Frontend + - [Blade Templates](/docs/{{version}}/blade) + - [Localization](/docs/{{version}}/localization) + - [Frontend Scaffolding](/docs/{{version}}/frontend) + - [Compiling Assets](/docs/{{version}}/mix) +- Security + - [Authentication](/docs/{{version}}/authentication) + - [API Authentication](/docs/{{version}}/passport) + - [Authorization](/docs/{{version}}/authorization) + - [Encryption](/docs/{{version}}/encryption) + - [Hashing](/docs/{{version}}/hashing) + - [Password Reset](/docs/{{version}}/passwords) +- General Topics + - [Artisan Console](/docs/{{version}}/artisan) + - [Broadcasting](/docs/{{version}}/broadcasting) + - [Cache](/docs/{{version}}/cache) + - [Collections](/docs/{{version}}/collections) + - [Errors & Logging](/docs/{{version}}/errors) + - [Events](/docs/{{version}}/events) + - [File Storage](/docs/{{version}}/filesystem) + - [Helpers](/docs/{{version}}/helpers) + - [Mail](/docs/{{version}}/mail) + - [Notifications](/docs/{{version}}/notifications) + - [Packages](/docs/{{version}}/packages) + - [Queues](/docs/{{version}}/queues) + - [Scheduled Tasks](/docs/{{version}}/scheduling) - Database - - [Basic Usage](database.md) - - [Query Builder](queries.md) - - [Eloquent ORM](eloquent.md) - - [Schema Builder](schema.md) - - [Migrations & Seeding](migrations.md) - - [Redis](redis.md) -- Artisan CLI - - [Overview](artisan.md) - - [Development](commands.md) \ No newline at end of file + - [Getting Started](/docs/{{version}}/database) + - [Query Builder](/docs/{{version}}/queries) + - [Pagination](/docs/{{version}}/pagination) + - [Migrations](/docs/{{version}}/migrations) + - [Seeding](/docs/{{version}}/seeding) + - [Redis](/docs/{{version}}/redis) +- Eloquent ORM + - [Getting Started](/docs/{{version}}/eloquent) + - [Relationships](/docs/{{version}}/eloquent-relationships) + - [Collections](/docs/{{version}}/eloquent-collections) + - [Mutators](/docs/{{version}}/eloquent-mutators) + - [Serialization](/docs/{{version}}/eloquent-serialization) +- Testing + - [Getting Started](/docs/{{version}}/testing) + - [HTTP Tests](/docs/{{version}}/http-tests) + - [Browser Tests](/docs/{{version}}/dusk) + - [Database](/docs/{{version}}/database-testing) + - [Mocking](/docs/{{version}}/mocking) +- Official Packages + - [Cashier](/docs/{{version}}/billing) + - [Envoy](/docs/{{version}}/envoy) + - [Passport](/docs/{{version}}/passport) + - [Scout](/docs/{{version}}/scout) + - [Socialite](https://github.com/laravel/socialite) diff --git a/dusk.md b/dusk.md new file mode 100644 index 0000000..1010224 --- /dev/null +++ b/dusk.md @@ -0,0 +1,584 @@ +# Browser Tests (Laravel Dusk) + +- [Introduction](#introduction) +- [Installation](#installation) + - [Using Other Browsers](#using-other-browsers) +- [Getting Started](#getting-started) + - [Generating Tests](#generating-tests) + - [Running Tests](#running-tests) + - [Environment Handling](#environment-handling) + - [Creating Browsers](#creating-browsers) + - [Authentication](#authentication) +- [Interacting With Elements](#interacting-with-elements) + - [Clicking Links](#clicking-links) + - [Text, Values, & Attributes](#text-values-and-attributes) + - [Using Forms](#using-forms) + - [Attaching Files](#attaching-files) + - [Using The Keyboard](#using-the-keyboard) + - [Using The Mouse](#using-the-mouse) + - [Scoping Selectors](#scoping-selectors) + - [Waiting For Elements](#waiting-for-elements) +- [Available Assertions](#available-assertions) +- [Pages](#pages) + - [Generating Pages](#generating-pages) + - [Configuring Pages](#configuring-pages) + - [Navigating To Pages](#navigating-to-pages) + - [Shorthand Selectors](#shorthand-selectors) + - [Page Methods](#page-methods) + + +## Introduction + +Laravel Dusk provides an expressive, easy-to-use browser automation and testing API. By default, Dusk does not require you to install JDK or Selenium on your machine. Instead, Dusk uses a standalone [ChromeDriver](https://sites.google.com/a/chromium.org/chromedriver/home) installation. However, you are free to utilize any other Selenium compatible driver you wish. + + +## Installation + +To get started, you should add the `laravel/dusk` Composer dependency to your project: + + composer require laravel/dusk + +Once Dusk is installed, you should register the `Laravel\Dusk\DuskServiceProvider` service provider. You should register the provider within the `register` method of your `AppServiceProvider` in order to limit the environments in which Dusk is available, since it exposes the ability to login as other users: + + use Laravel\Dusk\DuskServiceProvider; + + /** + * Register any application services. + * + * @return void + */ + public function register() + { + if ($this->app->environment('local', 'testing')) { + $this->app->register(DuskServiceProvider::class); + } + } + +Next, run the `dusk:install` Artisan command: + + php artisan dusk:install + +A `Browser` directory will be created within your `tests` directory and will contain an example test. Next, set the `APP_URL` environment variable in your `.env` file. This value should match the URL you use to access your application in a browser. + +To run your tests, use the `dusk` Artisan command. The `dusk` command accepts any argument that is also accepted by the `phpunit` command: + + php artisan dusk + + +### Using Other Browsers + +By default, Dusk uses Google Chrome and a standalone [ChromeDriver](https://sites.google.com/a/chromium.org/chromedriver/home) installation to run your browser tests. However, you may start your own Selenium server and run your tests against any browser you wish. + +To get started, open your `tests/DuskTestCase.php` file, which is the base Dusk test case for your application. Within this file, you can remove the call to the `startChromeDriver` method. This will stop Dusk from automatically starting the ChromeDriver: + + /** + * Prepare for Dusk test execution. + * + * @beforeClass + * @return void + */ + public static function prepare() + { + // static::startChromeDriver(); + } + +Next, you may simply modify the `driver` method to connect to the URL and port of your choice. In addition, you may modify the "desired capabilities" that should be passed to the WebDriver: + + /** + * Create the RemoteWebDriver instance. + * + * @return \Facebook\WebDriver\Remote\RemoteWebDriver + */ + protected function driver() + { + return RemoteWebDriver::create( + 'http://localhost:4444', DesiredCapabilities::phantomjs() + ); + } + + +## Getting Started + + +### Generating Tests + +To generate a Dusk test, use the `dusk:make` Artisan command. The generated test will be placed in the `tests/Browser` directory: + + php artisan dusk:make LoginTest + + +### Running Tests + +To run your browser tests, use the `dusk` Artisan command: + + php artisan dusk + +The `dusk` command accepts any argument that is normally accepted by the PHPUnit test runner, allowing you to only run the tests for a given [group](https://phpunit.de/manual/current/en/appendixes.annotations.html#appendixes.annotations.group), etc: + + php artisan dusk --group=foo + +#### Manually Starting ChromeDriver + +By default, Dusk will automatically attempt to start ChromeDriver. If this does not work for your particular system, you may manually start ChromeDriver before running the `dusk` command. If you choose to start ChromeDriver manually, you should comment out the following line of your `tests/DuskTestCase.php` file: + + /** + * Prepare for Dusk test execution. + * + * @beforeClass + * @return void + */ + public static function prepare() + { + // static::startChromeDriver(); + } + +In addition, if you start ChromeDriver on a port other than 9515, you should modify the `driver` method of the same class: + + /** + * Create the RemoteWebDriver instance. + * + * @return \Facebook\WebDriver\Remote\RemoteWebDriver + */ + protected function driver() + { + return RemoteWebDriver::create( + 'http://localhost:9515', DesiredCapabilities::chrome() + ); + } + + +### Environment Handling + +To force Dusk to use its own environment file when running tests, create a `.env.dusk.{environment}` file in the root of your project. For example, if you will be initiating the `dusk` command from your `local` environment, you should create a `.env.dusk.local` file. + +When running tests, Dusk will back-up your `.env` file and rename your Dusk environment to `.env`. Once the tests have completed, your `.env` file will be restored. + + +### Creating Browsers + +To get started, let's write a test that verifies we can log into our application. After generating a test, we can modify it to navigate to the login page, enter some credentials, and click the "Login" button. To create a browser instance, call the `browse` method: + + create([ + 'email' => 'taylor@laravel.com', + ]); + + $this->browse(function ($browser) use ($user) { + $browser->visit('/login') + ->type('email', $user->email) + ->type('password', 'secret') + ->press('Login') + ->assertPathIs('/home'); + }); + } + } + +As you can see in the example above, the `browse` method accepts a callback. A browser instance will automatically be passed to this callback by Dusk and is the main object used to interact with and make assertions against your application. + +> {tip} This test can be used to test the login screen generated by the `make:auth` Artisan command. + +#### Creating Multiple Browsers + +Sometimes you may need multiple browsers in order to properly carry out a test. For example, multiple browsers may be needed to test a chat screen that interacts with websockets. To create multiple browsers, simply "ask" for more than one browser in the signature of the callback given to the `browse` method: + + $this->browse(function ($first, $second) { + $first->loginAs(User::find(1)) + ->visit('/home') + ->waitForText('Message'); + + $second->loginAs(User::find(2)) + ->visit('/home') + ->waitForText('Message') + ->type('message', 'Hey Taylor') + ->press('Send'); + + $first->waitForText('Hey Taylor') + ->assertSee('Jeffrey Way'); + }); + + +### Authentication + +Often, you will be testing pages that require authentication. You can use Dusk's `loginAs` method in order to avoid interacting with the login screen during every test. The `loginAs` method accepts a user ID or user model instance: + + $this->browse(function ($first, $second) { + $first->loginAs(User::find(1)) + ->visit('/home'); + }); + + +## Interacting With Elements + + +### Clicking Links + +To click a link, you may use the `clickLink` method on the browser instance. The `clickLink` method will click the link that has the given display text: + + $browser->clickLink($linkText); + +> {note} This method interacts with jQuery. If jQuery is not available on the page, Dusk will automatically inject it into the page so it is available for the test's duration. + + +### Text, Values, & Attributes + +#### Retrieving & Setting Values + +Dusk provides several methods for interacting with the current display text, value, and attributes of elements on the page. For example, to get the "value" of an element that matches a given selector, use the `value` method: + + // Retrieve the value... + $value = $browser->value('selector'); + + // Set the value... + $browser->value('selector', 'value'); + +#### Retrieving Text + +The `text` method may be used to retrieve the display text of an element that matches the given selector: + + $text = $browser->text('selector'); + +#### Retrieving Attributes + +Finally, the `attribute` method may be used to retrieve an attribute of an element matching the given selector: + + $attribute = $browser->attribute('selector', 'value'); + + +### Using Forms + +#### Typing Values + +Dusk provides a variety of methods for interacting with forms and input elements. First, let's take a look at an example of typing text into an input field: + + $browser->type('email', 'taylor@laravel.com'); + +Note that, although the method accepts one if necessary, we are not required to pass a CSS selector into the `type` method. If a CSS selector is not provided, Dusk will search for an input field with the given `name` attribute. Finally, Dusk will attempt to find a `textarea` with the given `name` attribute. + +You may "clear" the value of an input using the `clear` method: + + $browser->clear('email'); + +#### Dropdowns + +To select a value in a dropdown selection box, you may use the `select` method. Like the `type` method, the `select` method does not require a full CSS selector. When passing a value to the `select` method, you should pass the underlying option value instead of the display text: + + $browser->select('size', 'Large'); + +#### Checkboxes + +To "check" a checkbox field, you may use the `check` method. Like many other input related methods, a full CSS selector is not required. If an exact selector match can't be found, Dusk will search for a checkbox with a matching `name` attribute: + + $browser->check('terms'); + + $browser->uncheck('terms'); + +#### Radio Buttons + +To "select" a radio button option, you may use the `radio` method. Like many other input related methods, a full CSS selector is not required. If an exact selector match can't be found, Dusk will search for a radio with matching `name` and `value` attributes: + + $browser->radio('version', 'php7'); + + +### Attaching Files + +The `attach` method may be used to attach a file to a `file` input element. Like many other input related methods, a full CSS selector is not required. If an exact selector match can't be found, Dusk will search for a file input with matching `name` attribute: + + $browser->attach('photo', __DIR__.'/photos/me.png'); + + +### Using The Keyboard + +The `keys` method allows you to provide more complex input sequences to a given element than normally allowed by the `type` method. For example, you may hold modifier keys entering values. In this example, the `shift` key will be held while `taylor` is entered into the element matching the given selector. After `taylor` is typed, `otwell` will be typed without any modifier keys: + + $browser->keys('selector', ['{shift}', 'taylor'], 'otwell'); + +You may even send a "hot key" to the primary CSS selector that contains your application: + + $browser->keys('.app', ['{command}', 'j']); + +> {tip} All modifier keys are wrapped in `{}` characters, and match the constants defined in the `Facebook\WebDriver\WebDriverKeys` class, which can be [found on GitHub](https://github.com/facebook/php-webdriver/blob/community/lib/WebDriverKeys.php). + + +### Using The Mouse + +#### Clicking On Elements + +The `click` method may be used to "click" on an element matching the given selector: + + $browser->click('.selector'); + +#### Mouseover + +The `mouseover` method may be used when you need to move the mouse over an element matching the given selector: + + $browser->mouseover('.selector'); + +#### Drag & Drop + +The `drag` method may be used to drag an element matching the given selector to another element: + + $browser->drag('.from-selector', '.to-selector'); + + +### Scoping Selectors + +Sometimes you may wish to perform several operations while scoping all of the operations within a given selector. For example, you may wish to assert that some text exists only within a table and then click a button within that table. You may use the `with` method to accomplish this. All operations performed within the callback given to the `with` method will be scoped to the original selector: + + $browser->with('.table', function ($table) { + $table->assertSee('Hello World') + ->clickLink('Delete'); + }); + + +### Waiting For Elements + +When testing applications that use JavaScript extensively, it often becomes necessary to "wait" for certain elements or data to be available before proceeding with a test. Dusk makes this a cinch. Using a variety of methods, you may wait for elements to be visible on the page or even wait until a given JavaScript expression evaluates to `true`. + +#### Waiting + +If you need to pause the test for a given number of milliseconds, use the `pause` method: + + $browser->pause(1000); + +#### Waiting For Selectors + +The `waitFor` method may be used to pause the execution of the test until the element matching the given CSS selector is displayed on the page. By default, this will pause the test for a maximum of five seconds before throwing an exception. If necessary, you may pass a custom timeout threshold as the second argument to the method: + + // Wait a maximum of five seconds for the selector... + $browser->waitFor('.selector'); + + // Wait a maximum of one second for the selector... + $browser->waitFor('.selector', 1); + +You may also wait until the given selector is missing from the page: + + $browser->waitUntilMissing('.selector'); + + $browser->waitUntilMissing('.selector', 1); + +#### Scoping Selectors When Available + +Occasionally, you may wish to wait for a given selector and then interact with the element matching the selector. For example, you may wish to wait until a modal window is available and then press the "OK" button within the modal. The `whenAvailable` method may be used in this case. All element operations performed within the given callback will be scoped to the original selector: + + $browser->whenAvailable('.modal', function ($modal) { + $modal->assertSee('Hello World') + ->press('OK'); + }); + +#### Waiting For Text + +The `waitForText` method may be used to wait until the given text is displayed on the page: + + // Wait a maximum of five seconds for the text... + $browser->waitForText('Hello World'); + + // Wait a maximum of one second for the text... + $browser->waitForText('Hello World', 1); + +#### Waiting For Links + +The `waitForLink` method may be used to wait until the given link text is displayed on the page: + + // Wait a maximum of five seconds for the link... + $browser->waitForLink('Create'); + + // Wait a maximum of one second for the link... + $browser->waitForLink('Create', 1); + +#### Waiting On JavaScript Expressions + +Sometimes you may wish to pause the execution of a test until a given JavaScript expression evaluates to `true`. You may easily accomplish this using the `waitUntil` method. When passing an expression to this method, you do not need to include the `return` keyword or an ending semi-colon: + + // Wait a maximum of five seconds for the expression to be true... + $browser->waitUntil('App.dataLoaded'); + + $browser->waitUntil('App.data.servers.length > 0'); + + // Wait a maximum of one second for the expression to be true... + $browser->waitUntil('App.data.servers.length > 0', 1); + + +## Available Assertions + +Dusk provides a variety of assertions that you may make against your application. All of the available assertions are documented in the table below: + +Assertion | Description +------------- | ------------- +`$browser->assertTitle($title)` | Assert the page title matches the given text. +`$browser->assertTitleContains($title)` | Assert the page title contains the given text. +`$browser->assertPathIs('/home')` | Assert the current path matches the given path. +`$browser->assertHasCookie($name)` | Assert the given cookie is present. +`$browser->assertCookieValue($name, $value)` | Assert a cookie has a given value. +`$browser->assertPlainCookieValue($name, $value)` | Assert an unencrypted cookie has a given value. +`$browser->assertSee($text)` | Assert the given text is present on the page. +`$browser->assertDontSee($text)` | Assert the given text is not present on the page. +`$browser->assertSeeIn($selector, $text)` | Assert the given text is present within the selector. +`$browser->assertDontSeeIn($selector, $text)` | Assert the given text is not present within the selector. +`$browser->assertSeeLink($linkText)` | Assert the given link is present on the page. +`$browser->assertDontSeeLink($linkText)` | Assert the given link is not present on the page. +`$browser->assertInputValue($field, $value)` | Assert the given input field has the given value. +`$browser->assertInputValueIsNot($field, $value)` | Assert the given input field does not have the given value. +`$browser->assertChecked($field)` | Assert the given checkbox is checked. +`$browser->assertNotChecked($field)` | Assert the given checkbox is not checked. +`$browser->assertSelected($field, $value)` | Assert the given dropdown has the given value selected. +`$browser->assertNotSelected($field, $value)` | Assert the given dropdown does not have the given value selected. +`$browser->assertValue($selector, $value)` | Assert the element matching the given selector has the given value. +`$browser->assertVisible($selector)` | Assert the element matching the given selector is visible. +`$browser->assertMissing($selector)` | Assert the element matching the given selector is not visible. + + +## Pages + +Sometimes, tests require several complicated actions to be performed in sequence. This can make your tests harder to read and understand. Pages allow you to define expressive actions that may then be performed on a given page using a single method. Pages also allow you to define short-cuts to common selectors for your application or a single page. + + +### Generating Pages + +To generate a page object, use the `dusk:page` Artisan command. All page objects will be placed in the `tests/Browser/Pages` directory: + + php artisan dusk:page Login + + +### Configuring Pages + +By default, pages have three methods: `url`, `assert`, and `selectors`. We will discuss the `url` and `assert` methods now. The `selectors` method will be [discussed in more detail below](#shorthand-selectors). + +#### The `url` Method + +The `url` method should return the path of the URL that represents the page. Dusk will use this URL when navigating to the page in the browser: + + /** + * Get the URL for the page. + * + * @return string + */ + public function url() + { + return '/login'; + } + +#### The `assert` Method + +The `assert` method may make any assertions necessary to verify that the browser is actually on the given page. Completing this method is not necessary; however, you are free to make these assertions if you wish. These assertions will be run automatically when navigating to the page: + + /** + * Assert that the browser is on the page. + * + * @return void + */ + public function assert(Browser $browser) + { + $browser->assertPathIs($this->url()); + } + + +### Navigating To Pages + +Once a page has been configured, you may navigate to it using the `visit` method: + + use Tests\Browser\Pages\Login; + + $browser->visit(new Login); + +Sometimes you may already be on a given page and need to "load" the page's selectors and methods into the current test context. This is common when pressing a button and being redirected to a given page without explicitly navigating to it. In this situation, you may use the `on` method to load the page: + + use Tests\Browser\Pages\CreatePlaylist; + + $browser->visit('/dashboard') + ->clickLink('Create Playlist') + ->on(new CreatePlaylist) + ->assertSee('@create'); + + +### Shorthand Selectors + +The `selectors` method of pages allows you to define quick, easy-to-remember shortcuts for any CSS selector on your page. For example, let's define a shortcut for the "email" input field of the application's login page: + + /** + * Get the element shortcuts for the page. + * + * @return array + */ + public function elements() + { + return [ + '@email' => 'input[name=email]', + ]; + } + +Now, you may use this shorthand selector anywhere you would use a full CSS selector: + + $browser->type('@email', 'taylor@laravel.com'); + +#### Global Shorthand Selectors + +After installing Dusk, a base `Page` class will be placed in your `tests/Browser/Pages` directory. This class contains a `siteElements` method which may be used to define global shorthand selectors that should be available on every page throughout your application: + + /** + * Get the global element shortcuts for the site. + * + * @return array + */ + public static function siteElements() + { + return [ + '@element' => '#selector', + ]; + } + + +### Page Methods + +In addition to the default methods defined on pages, you may define additional methods which may be used throughout your tests. For example, let's imagine we are building a music management application. A common action for one page of the application might be to create a playlist. Instead of re-writing the logic to create a playlist in each test, you may define a `createPlaylist` method on a page class: + + type('name', $name) + ->check('share') + ->press('Create Playlist'); + } + } + +Once the method has been defined, you may use it within any test that utilizes the page. The browser instance will automatically be passed to the page method: + + use Tests\Browser\Pages\Dashboard; + + $browser->visit(new Dashboard) + ->createPlaylist('My Playlist') + ->assertSee('My Playlist'); diff --git a/eloquent-collections.md b/eloquent-collections.md new file mode 100644 index 0000000..663e90d --- /dev/null +++ b/eloquent-collections.md @@ -0,0 +1,146 @@ +# Eloquent: Collections + +- [Introduction](#introduction) +- [Available Methods](#available-methods) +- [Custom Collections](#custom-collections) + + +## Introduction + +All multi-result sets returned by Eloquent are instances of the `Illuminate\Database\Eloquent\Collection` object, including results retrieved via the `get` method or accessed via a relationship. The Eloquent collection object extends the Laravel [base collection](/docs/{{version}}/collections), so it naturally inherits dozens of methods used to fluently work with the underlying array of Eloquent models. + +Of course, all collections also serve as iterators, allowing you to loop over them as if they were simple PHP arrays: + + $users = App\User::where('active', 1)->get(); + + foreach ($users as $user) { + echo $user->name; + } + +However, collections are much more powerful than arrays and expose a variety of map / reduce operations that may be chained using an intuitive interface. For example, let's remove all inactive models and gather the first name for each remaining user: + + $users = App\User::where('active', 1)->get(); + + $names = $users->reject(function ($user) { + return $user->active === false; + }) + ->map(function ($user) { + return $user->name; + }); + +> {note} While most Eloquent collection methods return a new instance of an Eloquent collection, the `pluck`, `keys`, `zip`, `collapse`, `flatten` and `flip` methods return a [base collection](/docs/{{version}}/collections) instance. Likewise, if a `map` operation returns a collection that does not contain any Eloquent models, it will be automatically cast to a base collection. + + +## Available Methods + +### The Base Collection + +All Eloquent collections extend the base [Laravel collection](/docs/{{version}}/collections) object; therefore, they inherit all of the powerful methods provided by the base collection class: + + + +
    + +[all](/docs/{{version}}/collections#method-all) +[avg](/docs/{{version}}/collections#method-avg) +[chunk](/docs/{{version}}/collections#method-chunk) +[collapse](/docs/{{version}}/collections#method-collapse) +[combine](/docs/{{version}}/collections#method-combine) +[contains](/docs/{{version}}/collections#method-contains) +[count](/docs/{{version}}/collections#method-count) +[diff](/docs/{{version}}/collections#method-diff) +[diffKeys](/docs/{{version}}/collections#method-diffkeys) +[each](/docs/{{version}}/collections#method-each) +[every](/docs/{{version}}/collections#method-every) +[except](/docs/{{version}}/collections#method-except) +[filter](/docs/{{version}}/collections#method-filter) +[first](/docs/{{version}}/collections#method-first) +[flatMap](/docs/{{version}}/collections#method-flatmap) +[flatten](/docs/{{version}}/collections#method-flatten) +[flip](/docs/{{version}}/collections#method-flip) +[forget](/docs/{{version}}/collections#method-forget) +[forPage](/docs/{{version}}/collections#method-forpage) +[get](/docs/{{version}}/collections#method-get) +[groupBy](/docs/{{version}}/collections#method-groupby) +[has](/docs/{{version}}/collections#method-has) +[implode](/docs/{{version}}/collections#method-implode) +[intersect](/docs/{{version}}/collections#method-intersect) +[isEmpty](/docs/{{version}}/collections#method-isempty) +[keyBy](/docs/{{version}}/collections#method-keyby) +[keys](/docs/{{version}}/collections#method-keys) +[last](/docs/{{version}}/collections#method-last) +[map](/docs/{{version}}/collections#method-map) +[max](/docs/{{version}}/collections#method-max) +[merge](/docs/{{version}}/collections#method-merge) +[min](/docs/{{version}}/collections#method-min) +[only](/docs/{{version}}/collections#method-only) +[pluck](/docs/{{version}}/collections#method-pluck) +[pop](/docs/{{version}}/collections#method-pop) +[prepend](/docs/{{version}}/collections#method-prepend) +[pull](/docs/{{version}}/collections#method-pull) +[push](/docs/{{version}}/collections#method-push) +[put](/docs/{{version}}/collections#method-put) +[random](/docs/{{version}}/collections#method-random) +[reduce](/docs/{{version}}/collections#method-reduce) +[reject](/docs/{{version}}/collections#method-reject) +[reverse](/docs/{{version}}/collections#method-reverse) +[search](/docs/{{version}}/collections#method-search) +[shift](/docs/{{version}}/collections#method-shift) +[shuffle](/docs/{{version}}/collections#method-shuffle) +[slice](/docs/{{version}}/collections#method-slice) +[sort](/docs/{{version}}/collections#method-sort) +[sortBy](/docs/{{version}}/collections#method-sortby) +[sortByDesc](/docs/{{version}}/collections#method-sortbydesc) +[splice](/docs/{{version}}/collections#method-splice) +[sum](/docs/{{version}}/collections#method-sum) +[take](/docs/{{version}}/collections#method-take) +[toArray](/docs/{{version}}/collections#method-toarray) +[toJson](/docs/{{version}}/collections#method-tojson) +[transform](/docs/{{version}}/collections#method-transform) +[union](/docs/{{version}}/collections#method-union) +[unique](/docs/{{version}}/collections#method-unique) +[values](/docs/{{version}}/collections#method-values) +[where](/docs/{{version}}/collections#method-where) +[whereStrict](/docs/{{version}}/collections#method-wherestrict) +[whereIn](/docs/{{version}}/collections#method-wherein) +[whereInLoose](/docs/{{version}}/collections#method-whereinloose) +[zip](/docs/{{version}}/collections#method-zip) + +
    + + +## Custom Collections + +If you need to use a custom `Collection` object with your own extension methods, you may override the `newCollection` method on your model: + + +## Introduction + +Accessors and mutators allow you to format Eloquent attribute values when you retrieve or set them on model instances. For example, you may want to use the [Laravel encrypter](/docs/{{version}}/encryption) to encrypt a value while it is stored in the database, and then automatically decrypt the attribute when you access it on an Eloquent model. + +In addition to custom accessors and mutators, Eloquent can also automatically cast date fields to [Carbon](https://github.com/briannesbitt/Carbon) instances or even [cast text fields to JSON](#attribute-casting). + + +## Accessors & Mutators + + +### Defining An Accessor + +To define an accessor, create a `getFooAttribute` method on your model where `Foo` is the "studly" cased name of the column you wish to access. In this example, we'll define an accessor for the `first_name` attribute. The accessor will automatically be called by Eloquent when attempting to retrieve the value of the `first_name` attribute: + + first_name; + + +### Defining A Mutator + +To define a mutator, define a `setFooAttribute` method on your model where `Foo` is the "studly" cased name of the column you wish to access. So, again, let's define a mutator for the `first_name` attribute. This mutator will be automatically called when we attempt to set the value of the `first_name` attribute on the model: + + attributes['first_name'] = strtolower($value); + } + } + +The mutator will receive the value that is being set on the attribute, allowing you to manipulate the value and set the manipulated value on the Eloquent model's internal `$attributes` property. So, for example, if we attempt to set the `first_name` attribute to `Sally`: + + $user = App\User::find(1); + + $user->first_name = 'Sally'; + +In this example, the `setFirstNameAttribute` function will be called with the value `Sally`. The mutator will then apply the `strtolower` function to the name and set its resulting value in the internal `$attributes` array. + + +## Date Mutators + +By default, Eloquent will convert the `created_at` and `updated_at` columns to instances of [Carbon](https://github.com/briannesbitt/Carbon), which extends the PHP `DateTime` class to provide an assortment of helpful methods. You may customize which dates are automatically mutated, and even completely disable this mutation, by overriding the `$dates` property of your model: + + deleted_at = Carbon::now(); + + $user->save(); + +As noted above, when retrieving attributes that are listed in your `$dates` property, they will automatically be cast to [Carbon](https://github.com/briannesbitt/Carbon) instances, allowing you to use any of Carbon's methods on your attributes: + + $user = App\User::find(1); + + return $user->deleted_at->getTimestamp(); + +#### Date Formats + +By default, timestamps are formatted as `'Y-m-d H:i:s'`. If you need to customize the timestamp format, set the `$dateFormat` property on your model. This property determines how date attributes are stored in the database, as well as their format when the model is serialized to an array or JSON: + + +## Attribute Casting + +The `$casts` property on your model provides a convenient method of converting attributes to common data types. The `$casts` property should be an array where the key is the name of the attribute being cast and the value is the type you wish to cast the column to. The supported cast types are: `integer`, `real`, `float`, `double`, `string`, `boolean`, `object`, `array`, `collection`, `date`, `datetime`, and `timestamp`. + +For example, let's cast the `is_admin` attribute, which is stored in our database as an integer (`0` or `1`) to a boolean value: + + 'boolean', + ]; + } + +Now the `is_admin` attribute will always be cast to a boolean when you access it, even if the underlying value is stored in the database as an integer: + + $user = App\User::find(1); + + if ($user->is_admin) { + // + } + + +### Array & JSON Casting + +The `array` cast type is particularly useful when working with columns that are stored as serialized JSON. For example, if your database has a `JSON` or `TEXT` field type that contains serialized JSON, adding the `array` cast to that attribute will automatically deserialize the attribute to a PHP array when you access it on your Eloquent model: + + 'array', + ]; + } + +Once the cast is defined, you may access the `options` attribute and it will automatically be deserialized from JSON into a PHP array. When you set the value of the `options` attribute, the given array will automatically be serialized back into JSON for storage: + + $user = App\User::find(1); + + $options = $user->options; + + $options['key'] = 'value'; + + $user->options = $options; + + $user->save(); diff --git a/eloquent-relationships.md b/eloquent-relationships.md new file mode 100644 index 0000000..f60a7ba --- /dev/null +++ b/eloquent-relationships.md @@ -0,0 +1,923 @@ +# Eloquent: Relationships + +- [Introduction](#introduction) +- [Defining Relationships](#defining-relationships) + - [One To One](#one-to-one) + - [One To Many](#one-to-many) + - [One To Many (Inverse)](#one-to-many-inverse) + - [Many To Many](#many-to-many) + - [Has Many Through](#has-many-through) + - [Polymorphic Relations](#polymorphic-relations) + - [Many To Many Polymorphic Relations](#many-to-many-polymorphic-relations) +- [Querying Relations](#querying-relations) + - [Relationship Methods Vs. Dynamic Properties](#relationship-methods-vs-dynamic-properties) + - [Querying Relationship Existence](#querying-relationship-existence) + - [Querying Relationship Absence](#querying-relationship-absence) + - [Counting Related Models](#counting-related-models) +- [Eager Loading](#eager-loading) + - [Constraining Eager Loads](#constraining-eager-loads) + - [Lazy Eager Loading](#lazy-eager-loading) +- [Inserting & Updating Related Models](#inserting-and-updating-related-models) + - [The `save` Method](#the-save-method) + - [The `create` Method](#the-create-method) + - [Belongs To Relationships](#updating-belongs-to-relationships) + - [Many To Many Relationships](#updating-many-to-many-relationships) +- [Touching Parent Timestamps](#touching-parent-timestamps) + + +## Introduction + +Database tables are often related to one another. For example, a blog post may have many comments, or an order could be related to the user who placed it. Eloquent makes managing and working with these relationships easy, and supports several different types of relationships: + +- [One To One](#one-to-one) +- [One To Many](#one-to-many) +- [Many To Many](#many-to-many) +- [Has Many Through](#has-many-through) +- [Polymorphic Relations](#polymorphic-relations) +- [Many To Many Polymorphic Relations](#many-to-many-polymorphic-relations) + + +## Defining Relationships + +Eloquent relationships are defined as methods on your Eloquent model classes. Since, like Eloquent models themselves, relationships also serve as powerful [query builders](/docs/{{version}}/queries), defining relationships as methods provides powerful method chaining and querying capabilities. For example, we may chain additional constraints on this `posts` relationship: + + $user->posts()->where('active', 1)->get(); + +But, before diving too deep into using relationships, let's learn how to define each type. + + +### One To One + +A one-to-one relationship is a very basic relation. For example, a `User` model might be associated with one `Phone`. To define this relationship, we place a `phone` method on the `User` model. The `phone` method should call the `hasOne` method and return its result: + + hasOne('App\Phone'); + } + } + +The first argument passed to the `hasOne` method is the name of the related model. Once the relationship is defined, we may retrieve the related record using Eloquent's dynamic properties. Dynamic properties allow you to access relationship methods as if they were properties defined on the model: + + $phone = User::find(1)->phone; + +Eloquent determines the foreign key of the relationship based on the model name. In this case, the `Phone` model is automatically assumed to have a `user_id` foreign key. If you wish to override this convention, you may pass a second argument to the `hasOne` method: + + return $this->hasOne('App\Phone', 'foreign_key'); + +Additionally, Eloquent assumes that the foreign key should have a value matching the `id` (or the custom `$primaryKey`) column of the parent. In other words, Eloquent will look for the value of the user's `id` column in the `user_id` column of the `Phone` record. If you would like the relationship to use a value other than `id`, you may pass a third argument to the `hasOne` method specifying your custom key: + + return $this->hasOne('App\Phone', 'foreign_key', 'local_key'); + +#### Defining The Inverse Of The Relationship + +So, we can access the `Phone` model from our `User`. Now, let's define a relationship on the `Phone` model that will let us access the `User` that owns the phone. We can define the inverse of a `hasOne` relationship using the `belongsTo` method: + + belongsTo('App\User'); + } + } + +In the example above, Eloquent will try to match the `user_id` from the `Phone` model to an `id` on the `User` model. Eloquent determines the default foreign key name by examining the name of the relationship method and suffixing the method name with `_id`. However, if the foreign key on the `Phone` model is not `user_id`, you may pass a custom key name as the second argument to the `belongsTo` method: + + /** + * Get the user that owns the phone. + */ + public function user() + { + return $this->belongsTo('App\User', 'foreign_key'); + } + +If your parent model does not use `id` as its primary key, or you wish to join the child model to a different column, you may pass a third argument to the `belongsTo` method specifying your parent table's custom key: + + /** + * Get the user that owns the phone. + */ + public function user() + { + return $this->belongsTo('App\User', 'foreign_key', 'other_key'); + } + + +### One To Many + +A "one-to-many" relationship is used to define relationships where a single model owns any amount of other models. For example, a blog post may have an infinite number of comments. Like all other Eloquent relationships, one-to-many relationships are defined by placing a function on your Eloquent model: + + hasMany('App\Comment'); + } + } + +Remember, Eloquent will automatically determine the proper foreign key column on the `Comment` model. By convention, Eloquent will take the "snake case" name of the owning model and suffix it with `_id`. So, for this example, Eloquent will assume the foreign key on the `Comment` model is `post_id`. + +Once the relationship has been defined, we can access the collection of comments by accessing the `comments` property. Remember, since Eloquent provides "dynamic properties", we can access relationship methods as if they were defined as properties on the model: + + $comments = App\Post::find(1)->comments; + + foreach ($comments as $comment) { + // + } + +Of course, since all relationships also serve as query builders, you can add further constraints to which comments are retrieved by calling the `comments` method and continuing to chain conditions onto the query: + + $comments = App\Post::find(1)->comments()->where('title', 'foo')->first(); + +Like the `hasOne` method, you may also override the foreign and local keys by passing additional arguments to the `hasMany` method: + + return $this->hasMany('App\Comment', 'foreign_key'); + + return $this->hasMany('App\Comment', 'foreign_key', 'local_key'); + + +### One To Many (Inverse) + +Now that we can access all of a post's comments, let's define a relationship to allow a comment to access its parent post. To define the inverse of a `hasMany` relationship, define a relationship function on the child model which calls the `belongsTo` method: + + belongsTo('App\Post'); + } + } + +Once the relationship has been defined, we can retrieve the `Post` model for a `Comment` by accessing the `post` "dynamic property": + + $comment = App\Comment::find(1); + + echo $comment->post->title; + +In the example above, Eloquent will try to match the `post_id` from the `Comment` model to an `id` on the `Post` model. Eloquent determines the default foreign key name by examining the name of the relationship method and suffixing the method name with `_id`. However, if the foreign key on the `Comment` model is not `post_id`, you may pass a custom key name as the second argument to the `belongsTo` method: + + /** + * Get the post that owns the comment. + */ + public function post() + { + return $this->belongsTo('App\Post', 'foreign_key'); + } + +If your parent model does not use `id` as its primary key, or you wish to join the child model to a different column, you may pass a third argument to the `belongsTo` method specifying your parent table's custom key: + + /** + * Get the post that owns the comment. + */ + public function post() + { + return $this->belongsTo('App\Post', 'foreign_key', 'other_key'); + } + + +### Many To Many + +Many-to-many relations are slightly more complicated than `hasOne` and `hasMany` relationships. An example of such a relationship is a user with many roles, where the roles are also shared by other users. For example, many users may have the role of "Admin". To define this relationship, three database tables are needed: `users`, `roles`, and `role_user`. The `role_user` table is derived from the alphabetical order of the related model names, and contains the `user_id` and `role_id` columns. + +Many-to-many relationships are defined by writing a method that returns the result of the `belongsToMany` method. For example, let's define the `roles` method on our `User` model: + + belongsToMany('App\Role'); + } + } + +Once the relationship is defined, you may access the user's roles using the `roles` dynamic property: + + $user = App\User::find(1); + + foreach ($user->roles as $role) { + // + } + +Of course, like all other relationship types, you may call the `roles` method to continue chaining query constraints onto the relationship: + + $roles = App\User::find(1)->roles()->orderBy('name')->get(); + +As mentioned previously, to determine the table name of the relationship's joining table, Eloquent will join the two related model names in alphabetical order. However, you are free to override this convention. You may do so by passing a second argument to the `belongsToMany` method: + + return $this->belongsToMany('App\Role', 'role_user'); + +In addition to customizing the name of the joining table, you may also customize the column names of the keys on the table by passing additional arguments to the `belongsToMany` method. The third argument is the foreign key name of the model on which you are defining the relationship, while the fourth argument is the foreign key name of the model that you are joining to: + + return $this->belongsToMany('App\Role', 'role_user', 'user_id', 'role_id'); + +#### Defining The Inverse Of The Relationship + +To define the inverse of a many-to-many relationship, you simply place another call to `belongsToMany` on your related model. To continue our user roles example, let's define the `users` method on the `Role` model: + + belongsToMany('App\User'); + } + } + +As you can see, the relationship is defined exactly the same as its `User` counterpart, with the exception of simply referencing the `App\User` model. Since we're reusing the `belongsToMany` method, all of the usual table and key customization options are available when defining the inverse of many-to-many relationships. + +#### Retrieving Intermediate Table Columns + +As you have already learned, working with many-to-many relations requires the presence of an intermediate table. Eloquent provides some very helpful ways of interacting with this table. For example, let's assume our `User` object has many `Role` objects that it is related to. After accessing this relationship, we may access the intermediate table using the `pivot` attribute on the models: + + $user = App\User::find(1); + + foreach ($user->roles as $role) { + echo $role->pivot->created_at; + } + +Notice that each `Role` model we retrieve is automatically assigned a `pivot` attribute. This attribute contains a model representing the intermediate table, and may be used like any other Eloquent model. + +By default, only the model keys will be present on the `pivot` object. If your pivot table contains extra attributes, you must specify them when defining the relationship: + + return $this->belongsToMany('App\Role')->withPivot('column1', 'column2'); + +If you want your pivot table to have automatically maintained `created_at` and `updated_at` timestamps, use the `withTimestamps` method on the relationship definition: + + return $this->belongsToMany('App\Role')->withTimestamps(); + +#### Filtering Relationships Via Intermediate Table Columns + +You can also filter the results returned by `belongsToMany` using the `wherePivot` and `wherePivotIn` methods when defining the relationship: + + return $this->belongsToMany('App\Role')->wherePivot('approved', 1); + + return $this->belongsToMany('App\Role')->wherePivotIn('priority', [1, 2]); + +#### Defining Custom Intermediate Table Models + +If you would like to define a custom model to represent the intermediate table of your relationship, you may call the `using` method when defining the relationship. All custom models used to represent intermediate tables of relationships must extend the `Illuminate\Database\Eloquent\Relations\Pivot` class: + + belongsToMany('App\User')->using('App\UserRole'); + } + } + + +### Has Many Through + +The "has-many-through" relationship provides a convenient shortcut for accessing distant relations via an intermediate relation. For example, a `Country` model might have many `Post` models through an intermediate `User` model. In this example, you could easily gather all blog posts for a given country. Let's look at the tables required to define this relationship: + + countries + id - integer + name - string + + users + id - integer + country_id - integer + name - string + + posts + id - integer + user_id - integer + title - string + +Though `posts` does not contain a `country_id` column, the `hasManyThrough` relation provides access to a country's posts via `$country->posts`. To perform this query, Eloquent inspects the `country_id` on the intermediate `users` table. After finding the matching user IDs, they are used to query the `posts` table. + +Now that we have examined the table structure for the relationship, let's define it on the `Country` model: + + hasManyThrough('App\Post', 'App\User'); + } + } + +The first argument passed to the `hasManyThrough` method is the name of the final model we wish to access, while the second argument is the name of the intermediate model. + +Typical Eloquent foreign key conventions will be used when performing the relationship's queries. If you would like to customize the keys of the relationship, you may pass them as the third and fourth arguments to the `hasManyThrough` method. The third argument is the name of the foreign key on the intermediate model, the fourth argument is the name of the foreign key on the final model, and the fifth argument is the local key: + + class Country extends Model + { + public function posts() + { + return $this->hasManyThrough( + 'App\Post', 'App\User', + 'country_id', 'user_id', 'id' + ); + } + } + + +### Polymorphic Relations + +#### Table Structure + +Polymorphic relations allow a model to belong to more than one other model on a single association. For example, imagine users of your application can "comment" both posts and videos. Using polymorphic relationships, you can use a single `comments` table for both of these scenarios. First, let's examine the table structure required to build this relationship: + + posts + id - integer + title - string + body - text + + videos + id - integer + title - string + url - string + + comments + id - integer + body - text + commentable_id - integer + commentable_type - string + +Two important columns to note are the `commentable_id` and `commentable_type` columns on the `comments` table. The `commentable_id` column will contain the ID value of the post or video, while the `commentable_type` column will contain the class name of the owning model. The `commentable_type` column is how the ORM determines which "type" of owning model to return when accessing the `commentable` relation. + +#### Model Structure + +Next, let's examine the model definitions needed to build this relationship: + + morphTo(); + } + } + + class Post extends Model + { + /** + * Get all of the post's comments. + */ + public function comments() + { + return $this->morphMany('App\Comment', 'commentable'); + } + } + + class Video extends Model + { + /** + * Get all of the video's comments. + */ + public function comments() + { + return $this->morphMany('App\Comment', 'commentable'); + } + } + +#### Retrieving Polymorphic Relations + +Once your database table and models are defined, you may access the relationships via your models. For example, to access all of the comments for a post, we can simply use the `comments` dynamic property: + + $post = App\Post::find(1); + + foreach ($post->comments as $comment) { + // + } + +You may also retrieve the owner of a polymorphic relation from the polymorphic model by accessing the name of the method that performs the call to `morphTo`. In our case, that is the `commentable` method on the `Comment` model. So, we will access that method as a dynamic property: + + $comment = App\Comment::find(1); + + $commentable = $comment->commentable; + +The `commentable` relation on the `Comment` model will return either a `Post` or `Video` instance, depending on which type of model owns the comment. + +#### Custom Polymorphic Types + +By default, Laravel will use the fully qualified class name to store the type of the related model. For instance, given the example above where a `Comment` may belong to a `Post` or a `Video`, the default `commentable_type` would be either `App\Post` or `App\Video`, respectively. However, you may wish to decouple your database from your application's internal structure. In that case, you may define a relationship "morph map" to instruct Eloquent to use a custom name for each model instead of the class name: + + use Illuminate\Database\Eloquent\Relations\Relation; + + Relation::morphMap([ + 'posts' => 'App\Post', + 'videos' => 'App\Video', + ]); + +You may register the `morphMap` in the `boot` function of your `AppServiceProvider` or create a separate service provider if you wish. + + +### Many To Many Polymorphic Relations + +#### Table Structure + +In addition to traditional polymorphic relations, you may also define "many-to-many" polymorphic relations. For example, a blog `Post` and `Video` model could share a polymorphic relation to a `Tag` model. Using a many-to-many polymorphic relation allows you to have a single list of unique tags that are shared across blog posts and videos. First, let's examine the table structure: + + posts + id - integer + name - string + + videos + id - integer + name - string + + tags + id - integer + name - string + + taggables + tag_id - integer + taggable_id - integer + taggable_type - string + +#### Model Structure + +Next, we're ready to define the relationships on the model. The `Post` and `Video` models will both have a `tags` method that calls the `morphToMany` method on the base Eloquent class: + + morphToMany('App\Tag', 'taggable'); + } + } + +#### Defining The Inverse Of The Relationship + +Next, on the `Tag` model, you should define a method for each of its related models. So, for this example, we will define a `posts` method and a `videos` method: + + morphedByMany('App\Post', 'taggable'); + } + + /** + * Get all of the videos that are assigned this tag. + */ + public function videos() + { + return $this->morphedByMany('App\Video', 'taggable'); + } + } + +#### Retrieving The Relationship + +Once your database table and models are defined, you may access the relationships via your models. For example, to access all of the tags for a post, you can simply use the `tags` dynamic property: + + $post = App\Post::find(1); + + foreach ($post->tags as $tag) { + // + } + +You may also retrieve the owner of a polymorphic relation from the polymorphic model by accessing the name of the method that performs the call to `morphedByMany`. In our case, that is the `posts` or `videos` methods on the `Tag` model. So, you will access those methods as dynamic properties: + + $tag = App\Tag::find(1); + + foreach ($tag->videos as $video) { + // + } + + +## Querying Relations + +Since all types of Eloquent relationships are defined via methods, you may call those methods to obtain an instance of the relationship without actually executing the relationship queries. In addition, all types of Eloquent relationships also serve as [query builders](/docs/{{version}}/queries), allowing you to continue to chain constraints onto the relationship query before finally executing the SQL against your database. + +For example, imagine a blog system in which a `User` model has many associated `Post` models: + + hasMany('App\Post'); + } + } + +You may query the `posts` relationship and add additional constraints to the relationship like so: + + $user = App\User::find(1); + + $user->posts()->where('active', 1)->get(); + +You are able to use any of the [query builder](/docs/{{version}}/queries) methods on the relationship, so be sure to explore the query builder documentation to learn about all of the methods that are available to you. + + +### Relationship Methods Vs. Dynamic Properties + +If you do not need to add additional constraints to an Eloquent relationship query, you may simply access the relationship as if it were a property. For example, continuing to use our `User` and `Post` example models, we may access all of a user's posts like so: + + $user = App\User::find(1); + + foreach ($user->posts as $post) { + // + } + +Dynamic properties are "lazy loading", meaning they will only load their relationship data when you actually access them. Because of this, developers often use [eager loading](#eager-loading) to pre-load relationships they know will be accessed after loading the model. Eager loading provides a significant reduction in SQL queries that must be executed to load a model's relations. + + +### Querying Relationship Existence + +When accessing the records for a model, you may wish to limit your results based on the existence of a relationship. For example, imagine you want to retrieve all blog posts that have at least one comment. To do so, you may pass the name of the relationship to the `has` method: + + // Retrieve all posts that have at least one comment... + $posts = App\Post::has('comments')->get(); + +You may also specify an operator and count to further customize the query: + + // Retrieve all posts that have three or more comments... + $posts = Post::has('comments', '>=', 3)->get(); + +Nested `has` statements may also be constructed using "dot" notation. For example, you may retrieve all posts that have at least one comment and vote: + + // Retrieve all posts that have at least one comment with votes... + $posts = Post::has('comments.votes')->get(); + +If you need even more power, you may use the `whereHas` and `orWhereHas` methods to put "where" conditions on your `has` queries. These methods allow you to add customized constraints to a relationship constraint, such as checking the content of a comment: + + // Retrieve all posts with at least one comment containing words like foo% + $posts = Post::whereHas('comments', function ($query) { + $query->where('content', 'like', 'foo%'); + })->get(); + + +### Querying Relationship Absence + +When accessing the records for a model, you may wish to limit your results based on the absence of a relationship. For example, imagine you want to retrieve all blog posts that **don't** have any comments. To do so, you may pass the name of the relationship to the `doesntHave` method: + + $posts = App\Post::doesntHave('comments')->get(); + +If you need even more power, you may use the `whereDoesntHave` method to put "where" conditions on your `doesntHave` queries. This method allows you to add customized constraints to a relationship constraint, such as checking the content of a comment: + + $posts = Post::whereDoesntHave('comments', function ($query) { + $query->where('content', 'like', 'foo%'); + })->get(); + + +### Counting Related Models + +If you want to count the number of results from a relationship without actually loading them you may use the `withCount` method, which will place a `{relation}_count` column on your resulting models. For example: + + $posts = App\Post::withCount('comments')->get(); + + foreach ($posts as $post) { + echo $post->comments_count; + } + +You may add the "counts" for multiple relations as well as add constraints to the queries: + + $posts = Post::withCount(['votes', 'comments' => function ($query) { + $query->where('content', 'like', 'foo%'); + }])->get(); + + echo $posts[0]->votes_count; + echo $posts[0]->comments_count; + + +## Eager Loading + +When accessing Eloquent relationships as properties, the relationship data is "lazy loaded". This means the relationship data is not actually loaded until you first access the property. However, Eloquent can "eager load" relationships at the time you query the parent model. Eager loading alleviates the N + 1 query problem. To illustrate the N + 1 query problem, consider a `Book` model that is related to `Author`: + + belongsTo('App\Author'); + } + } + +Now, let's retrieve all books and their authors: + + $books = App\Book::all(); + + foreach ($books as $book) { + echo $book->author->name; + } + +This loop will execute 1 query to retrieve all of the books on the table, then another query for each book to retrieve the author. So, if we have 25 books, this loop would run 26 queries: 1 for the original book, and 25 additional queries to retrieve the author of each book. + +Thankfully, we can use eager loading to reduce this operation to just 2 queries. When querying, you may specify which relationships should be eager loaded using the `with` method: + + $books = App\Book::with('author')->get(); + + foreach ($books as $book) { + echo $book->author->name; + } + +For this operation, only two queries will be executed: + + select * from books + + select * from authors where id in (1, 2, 3, 4, 5, ...) + +#### Eager Loading Multiple Relationships + +Sometimes you may need to eager load several different relationships in a single operation. To do so, just pass additional arguments to the `with` method: + + $books = App\Book::with('author', 'publisher')->get(); + +#### Nested Eager Loading + +To eager load nested relationships, you may use "dot" syntax. For example, let's eager load all of the book's authors and all of the author's personal contacts in one Eloquent statement: + + $books = App\Book::with('author.contacts')->get(); + + +### Constraining Eager Loads + +Sometimes you may wish to eager load a relationship, but also specify additional query constraints for the eager loading query. Here's an example: + + $users = App\User::with(['posts' => function ($query) { + $query->where('title', 'like', '%first%'); + }])->get(); + +In this example, Eloquent will only eager load posts where the post's `title` column contains the word `first`. Of course, you may call other [query builder](/docs/{{version}}/queries) methods to further customize the eager loading operation: + + $users = App\User::with(['posts' => function ($query) { + $query->orderBy('created_at', 'desc'); + }])->get(); + + +### Lazy Eager Loading + +Sometimes you may need to eager load a relationship after the parent model has already been retrieved. For example, this may be useful if you need to dynamically decide whether to load related models: + + $books = App\Book::all(); + + if ($someCondition) { + $books->load('author', 'publisher'); + } + +If you need to set additional query constraints on the eager loading query, you may pass an array keyed by the relationships you wish to load. The array values should be `Closure` instances which receive the query instance: + + $books->load(['author' => function ($query) { + $query->orderBy('published_date', 'asc'); + }]); + + +## Inserting & Updating Related Models + + +### The Save Method + +Eloquent provides convenient methods for adding new models to relationships. For example, perhaps you need to insert a new `Comment` for a `Post` model. Instead of manually setting the `post_id` attribute on the `Comment`, you may insert the `Comment` directly from the relationship's `save` method: + + $comment = new App\Comment(['message' => 'A new comment.']); + + $post = App\Post::find(1); + + $post->comments()->save($comment); + +Notice that we did not access the `comments` relationship as a dynamic property. Instead, we called the `comments` method to obtain an instance of the relationship. The `save` method will automatically add the appropriate `post_id` value to the new `Comment` model. + +If you need to save multiple related models, you may use the `saveMany` method: + + $post = App\Post::find(1); + + $post->comments()->saveMany([ + new App\Comment(['message' => 'A new comment.']), + new App\Comment(['message' => 'Another comment.']), + ]); + + +### The Create Method + +In addition to the `save` and `saveMany` methods, you may also use the `create` method, which accepts an array of attributes, creates a model, and inserts it into the database. Again, the difference between `save` and `create` is that `save` accepts a full Eloquent model instance while `create` accepts a plain PHP `array`: + + $post = App\Post::find(1); + + $comment = $post->comments()->create([ + 'message' => 'A new comment.', + ]); + +Before using the `create` method, be sure to review the documentation on attribute [mass assignment](/docs/{{version}}/eloquent#mass-assignment). + + +### Belongs To Relationships + +When updating a `belongsTo` relationship, you may use the `associate` method. This method will set the foreign key on the child model: + + $account = App\Account::find(10); + + $user->account()->associate($account); + + $user->save(); + +When removing a `belongsTo` relationship, you may use the `dissociate` method. This method will set the relationship's foreign key to `null`: + + $user->account()->dissociate(); + + $user->save(); + + +### Many To Many Relationships + +#### Attaching / Detaching + +Eloquent also provides a few additional helper methods to make working with related models more convenient. For example, let's imagine a user can have many roles and a role can have many users. To attach a role to a user by inserting a record in the intermediate table that joins the models, use the `attach` method: + + $user = App\User::find(1); + + $user->roles()->attach($roleId); + +When attaching a relationship to a model, you may also pass an array of additional data to be inserted into the intermediate table: + + $user->roles()->attach($roleId, ['expires' => $expires]); + +Of course, sometimes it may be necessary to remove a role from a user. To remove a many-to-many relationship record, use the `detach` method. The `detach` method will remove the appropriate record out of the intermediate table; however, both models will remain in the database: + + // Detach a single role from the user... + $user->roles()->detach($roleId); + + // Detach all roles from the user... + $user->roles()->detach(); + +For convenience, `attach` and `detach` also accept arrays of IDs as input: + + $user = App\User::find(1); + + $user->roles()->detach([1, 2, 3]); + + $user->roles()->attach([1 => ['expires' => $expires], 2, 3]); + +#### Syncing Associations + +You may also use the `sync` method to construct many-to-many associations. The `sync` method accepts an array of IDs to place on the intermediate table. Any IDs that are not in the given array will be removed from the intermediate table. So, after this operation is complete, only the IDs in the given array will exist in the intermediate table: + + $user->roles()->sync([1, 2, 3]); + +You may also pass additional intermediate table values with the IDs: + + $user->roles()->sync([1 => ['expires' => true], 2, 3]); + +If you do not want to detach existing IDs, you may use the `syncWithoutDetaching` method: + + $user->roles()->syncWithoutDetaching([1, 2, 3]); + +#### Toggling Associations + +The many-to-many relationship also provides a `toggle` method which "toggles" the attachment status of the given IDs. If the given ID is currently attached, it will be detached. Likewise, if it is currently detached, it will be attached: + + $user->roles()->toggle([1, 2, 3]); + +#### Saving Additional Data On A Pivot Table + +When working with a many-to-many relationship, the `save` method accepts an array of additional intermediate table attributes as its second argument: + + App\User::find(1)->roles()->save($role, ['expires' => $expires]); + +#### Updating A Record On A Pivot Table + +If you need to update an existing row in your pivot table, you may use `updateExistingPivot` method. This method accepts the pivot record foreign key and an array of attributes to update: + + $user = App\User::find(1); + + $user->roles()->updateExistingPivot($roleId, $attributes); + + +## Touching Parent Timestamps + +When a model `belongsTo` or `belongsToMany` another model, such as a `Comment` which belongs to a `Post`, it is sometimes helpful to update the parent's timestamp when the child model is updated. For example, when a `Comment` model is updated, you may want to automatically "touch" the `updated_at` timestamp of the owning `Post`. Eloquent makes it easy. Just add a `touches` property containing the names of the relationships to the child model: + + belongsTo('App\Post'); + } + } + +Now, when you update a `Comment`, the owning `Post` will have its `updated_at` column updated as well, making it more convenient to know when to invalidate a cache of the `Post` model: + + $comment = App\Comment::find(1); + + $comment->text = 'Edit to this comment!'; + + $comment->save(); diff --git a/eloquent-serialization.md b/eloquent-serialization.md new file mode 100644 index 0000000..5d6a7a4 --- /dev/null +++ b/eloquent-serialization.md @@ -0,0 +1,147 @@ +# Eloquent: Serialization + +- [Introduction](#introduction) +- [Serializing Models & Collections](#serializing-models-and-collections) + - [Serializing To Arrays](#serializing-to-arrays) + - [Serializing To JSON](#serializing-to-json) +- [Hiding Attributes From JSON](#hiding-attributes-from-json) +- [Appending Values To JSON](#appending-values-to-json) + + +## Introduction + +When building JSON APIs, you will often need to convert your models and relationships to arrays or JSON. Eloquent includes convenient methods for making these conversions, as well as controlling which attributes are included in your serializations. + + +## Serializing Models & Collections + + +### Serializing To Arrays + +To convert a model and its loaded [relationships](/docs/{{version}}/eloquent-relationships) to an array, you should use the `toArray` method. This method is recursive, so all attributes and all relations (including the relations of relations) will be converted to arrays: + + $user = App\User::with('roles')->first(); + + return $user->toArray(); + +You may also convert entire [collections](/docs/{{version}}/eloquent-collections) of models to arrays: + + $users = App\User::all(); + + return $users->toArray(); + + +### Serializing To JSON + +To convert a model to JSON, you should use the `toJson` method. Like `toArray`, the `toJson` method is recursive, so all attributes and relations will be converted to JSON: + + $user = App\User::find(1); + + return $user->toJson(); + +Alternatively, you may cast a model or collection to a string, which will automatically call the `toJson` method on the model or collection: + + $user = App\User::find(1); + + return (string) $user; + +Since models and collections are converted to JSON when cast to a string, you can return Eloquent objects directly from your application's routes or controllers: + + Route::get('users', function () { + return App\User::all(); + }); + + +## Hiding Attributes From JSON + +Sometimes you may wish to limit the attributes, such as passwords, that are included in your model's array or JSON representation. To do so, add a `$hidden` property to your model: + + {note} When hiding relationships, use the relationship's method name, not its dynamic property name. + +Alternatively, you may use the `visible` property to define a white-list of attributes that should be included in your model's array and JSON representation. All other attributes will be hidden when the model is converted to an array or JSON: + + makeVisible('attribute')->toArray(); + +Likewise, if you would like to make some typically visible attributes hidden on a given model instance, you may use the `makeHidden` method. + + return $user->makeHidden('attribute')->toArray(); + + +## Appending Values To JSON + +Occasionally, when casting models to an array or JSON, you may wish to add attributes that do not have a corresponding column in your database. To do so, first define an [accessor](/docs/{{version}}/eloquent-mutators) for the value: + + attributes['admin'] == 'yes'; + } + } + +After creating the accessor, add the attribute name to the `appends` property on the model. Note that attribute names are typically referenced in "snake case", even though the accessor is defined using "camel case": + + -## အကြမ်းဖျင်း +## Introduction -Laravel တွင်ပါဝင်သည့် ရုုိးရှင်းပြီး လှပသပ်ရပ်သော Eloquent ORM သည် သင့် Database ကုုိ ActiveRecord ဖြင့် အခြေခံထား သဖြင့် အလွယ်တကူပင် အသုုံးပြုနုုိင်မည် ဖြစ်သည်။ Database မှ Table တစ်ခုုတုုိင်းကုုိ Model တစ်ခုု အနေဖြင့် သတ်မှတ်ကာ အသုုံးပြုရမည် ဖြစ်သည်။ +The Eloquent ORM included with Laravel provides a beautiful, simple ActiveRecord implementation for working with your database. Each database table has a corresponding "Model" which is used to interact with that table. Models allow you to query for data in your tables, as well as insert new records into the table. -အသုုံးမပြုခင် ပထမဆုုံး အနေဖြင့် `app/config/database.php` သုုိ ့သွားရောက်ကာ ကြိုတင် ပြင်ဆင်ရမည် ဖြစ်သည်။ +Before getting started, be sure to configure a database connection in `config/database.php`. For more information on configuring your database, check out [the documentation](/docs/{{version}}/database#configuration). - -## အခြေခံအသုုံးပြုပုုံ + +## Defining Models -စတင် အသုုံးပြုရန် Eloquent model တစ်ခုုကိုု တည်ဆောက်ရမည် ဖြစ်သည်။ ပုုံမှန်အားဖြင့် Models file များမှာ `app/models` အမည်ရှိသည့် Folder ထဲတွင် တည်ရှိမည် ဖြစ်သော်လည်း အလျဉ်းသင့်သလုုိ ပြင်ဆင်နုုိင်မည်ဖြစ်သည်။ ထုုိသုုိ ့ပြင်ဆင်နုုိင်ရန် အတွက် `composer.json` ထဲတွင် မိမိတုုိ ့ autoload လုုပ်ချင်သည့် file ၏ အမည်နှင့် တည်နေရာကိုု ထည့်သွင်းထားရမည် ဖြစ်သည်။ +To get started, let's create an Eloquent model. Models typically live in the `app` directory, but you are free to place them anywhere that can be auto-loaded according to your `composer.json` file. All Eloquent models extend `Illuminate\Database\Eloquent\Model` class. +The easiest way to create a model instance is using the `make:model` [Artisan command](/docs/{{version}}/artisan): -#### Eloquent Model တစ်ခုု Define ပြုလုုပ်ခြင်း + php artisan make:model User -class User extends Eloquent {} +If you would like to generate a [database migration](/docs/{{version}}/migrations) when you generate the model, you may use the `--migration` or `-m` option: -Eloquent Model တွင် မည့်သည့် table ကုုိ အသုုံးပြုမည်ကုုိ မကြေညာ ထားပါက Model အမည်၏ အများကိန်း ကုုိ အသုုံးပြုမည် ဖြစ်သည်။ ဥပမာ User.php ဟုု ကြေညာထားပါက Users table ဟုု အလုုိအလျောက် သတ်မှတ်မည် ဖြစ်သည်။ သုုိ ့မဟုုတ်ပဲ မိမိ စိတ်ကြိုက် အသုုံးပြုလုုိပါက အောက်ပါ အတုုိင်း သတ်မှတ်နုုိင်မည် ဖြစ်သည်။ + php artisan make:model User --migration -class User extends Eloquent { + php artisan make:model User -m -protected $table = 'my_users'; + +### Eloquent Model Conventions -} +Now, let's look at an example `Flight` model, which we will use to retrieve and store information from our `flights` database table: -> **မှတ်ချက်:** Eloquent အနေဖြင့် Primary Key column ဟုု `id` ဟုု အလုုိအလျောက် သတ်မှတ်ဖြစ်သော်လည်း အထက်က ကဲ့သုုိ ့ပင် မိမိစိတ်ကြိုက် column ကုုိ သတ်မှတ်နုုိင်သည်။ ထုုိကဲ့သုုိ ့ Database Connection ကုုိ `connection` ဟုုသည် property ကုုိ အသုုံးပြု ထပ်မံ သတ်မှတ်နုုိင်မည် ဖြစ်သည်။ + name); +Note that we did not tell Eloquent which table to use for our `Flight` model. By convention, the "snake case", plural name of the class will be used as the table name unless another name is explicitly specified. So, in this case, Eloquent will assume the `Flight` model stores records in the `flights` table. You may specify a custom table by defining a `table` property on your model: -> **Note:** [query builder] တွင် အသုုံးပြုနုုိင်သည့် method များ အားလုုံး (queries.md) Eloquent models တွင်လည်း ဆက်လက် အသုုံးပြုနုုိင်မည် ဖြစ်သည်။ + ', 100)->firstOrFail(); +#### Primary Keys -To register the error handler, listen for the `ModelNotFoundException` +Eloquent will also assume that each table has a primary key column named `id`. You may define a `$primaryKey` property to override this convention. -use Illuminate\Database\Eloquent\ModelNotFoundException; +In addition, Eloquent assumes that the primary key is an incrementing integer value, which means that by default the primary key will be cast to an `int` automatically. If you wish to use a non-incrementing or a non-numeric primary key you must set the public `$incrementing` property on your model to `false`. -App::error(function(ModelNotFoundException $e) -{ -return Response::make('Not Found', 404); -}); +#### Timestamps -#### Querying Using Eloquent Models ကုုိ အသုုံးပြုကာ Query များရေးသားခြင်း +By default, Eloquent expects `created_at` and `updated_at` columns to exist on your tables. If you do not wish to have these columns automatically managed by Eloquent, set the `$timestamps` property on your model to `false`: -$users = User::where('votes', '>', 100)->take(10)->get(); + name); -} + namespace App; -#### Eloquent ကို ပေါင်းစပ် အသုုံးပြုခြင်း + use Illuminate\Database\Eloquent\Model; + class Flight extends Model + { + /** + * Indicates if the model should be timestamped. + * + * @var bool + */ + public $timestamps = false; + } -သင့်အနေဖြင့် Query Builder function များဖြင့် Eloquent ကို ပေါင်းစပ် အသုုံးပြုနုုိင်သည်။ +If you need to customize the format of your timestamps, set the `$dateFormat` property on your model. This property determines how date attributes are stored in the database, as well as their format when the model is serialized to an array or JSON: -$count = User::where('votes', '>', 100)->count(); + ? and votes = 100', array(25))->get(); + class Flight extends Model + { + /** + * The storage format of the model's date columns. + * + * @var string + */ + protected $dateFormat = 'U'; + } -#### Results များကို ခွဲထုတ်ခြင်း +If you need to customize the names of the columns used to store the timestamps, you may set the `CREATED_AT` and `UPDATED_AT` constants in your model: -သင့်အနေဖြင့် ထောင်ပေါင်းများစွာသော Eloquent records များကို ထုတ်ယူလိုပါက `chunk` ဟုသော method ကို အသုံးပြု၍ Memory အသုံးပြုမှုကို လျော့ချနိုင်ပါသည်။ + find(1); + use Illuminate\Database\Eloquent\Model; - -## အမြောက်အများ ထည့်သွင်းခြင်း - - -Model အသစ်ကို တည်ဆောက်ပြီးပါက Constructor အနေဖြင့် ပါဝင်မည့် attribute များကို array အနေဖြင့် ထည့်သွင်းနိုင်ပါသည်။ -ထိုကဲ့သို ့ attribute များ ကို Model များမှ တဆင့် အမြောက်အများ ထည့်သွင်းနိုင်ခြင်းသည် အဆင်ပြေသော်လည်း User Input ကို မစစ်မဆေးပဲ အမြောက်အများထည့်သွင်းပါက လုံခြုံရေး ဆိုင်ရာ **ပြဿနာ** များရှိနိုင်ပါသည်။ ထိုကြောင့် default အနေဖြင့် Eloquent Model များအားလုံးတွင် ထိုသို ့ -ပြုလုပ်ခြင်းကို ဖွင့်မပေးထားပါ။ သို ့သော် ထို ့သို ့ပြုလုပ်ချင်ပါက `fillable` သို ့မဟုတ် `guarded` အစရှိသည့် attribute များကို သတ်မှတ်ထားရန် လိုပေမည်။ - -#### Defining Fillable Attributes On A Model - -The `fillable` property specifies which attributes should be mass-assignable. This can be set at the class or instance level. - -class User extends Eloquent { - -protected $fillable = array('first_name', 'last_name', 'email'); - -} - -အထက်က ဥပမာတွင် array တွင်ထည့်သွင်းထားသည့် attribute များသည် အမြောက်အများ ထည့်သွင်းနိုင်သည်။ - -#### Model တွင် တားမြစ် attribute များအား သတ်မှတ်ခြင်း - - -`fillable` ၏ ပြောင်းပြန်မှာ `guarded` ဖြစ်ပြီင်္း phone တစ်လုံး၏ "black-list" ကဲ့သို ့ အလုပ်လုပ်သည်။ - -class User extends Eloquent { - -protected $guarded = array('id', 'password'); - -} - -> **Note:** When using `guarded`, you should still never pass `Input::get()` or any raw array of user controlled input into a `save` or `update` method, as any column that is not guarded may be updated. - -#### အမြောက်အများ ထည့်သွင်းခြင်းမှ တားမြစ်ခြင်း - -အပေါ်မှ ဥပမာတွင် `id` နှင့် `password` field များမှာ အမြောက်အများ ထည့်သွင်းနိုင်မည် မဟုတ်ပေ။ အခြား attribute များမှာမူ အမြောက်အများ ထည့်သွင်းနိုင်မည် ဖြစ်သည်။ အကယ်၏ field အားလုံးကို တားမြစ်လိုပါက - -protected $guarded = array('*'); - - -## ထည့်သွင်း ၊ ပြင်ဆင် ၊ ဖျက်ပစ် - -Model မှ record အသစ်ကို တည်ဆောက်လိုပါက model instance တစ်ခုကို တည်ဆောက်ပြီး `save` method ကို အသုံးပြုနိုင်သည်။ - - -#### Model တွင် record များ ထည့်သွင်းခြင်း - -$user = new User; - -$user->name = 'John'; - -$user->save(); - -> **Note:** Typically, your Eloquent models will have auto-incrementing keys. However, if you wish to specify your own keys, set the `incrementing` property on your model to `false`. - -You may also use the `create` method to save a new model in a single line. The inserted model instance will be returned to you from the method. However, before doing so, you will need to specify either a `fillable` or `guarded` attribute on the model, as all Eloquent models protect against mass-assignment. - -After saving or creating a new model that uses auto-incrementing IDs, you may retrieve the ID by accessing the object's `id` attribute: - -$insertedId = $user->id; - -#### Setting The Guarded Attributes On The Model - -class User extends Eloquent { - -protected $guarded = array('id', 'account_id'); - -} - -#### Using The Model Create Method - -// Create a new user in the database... -$user = User::create(array('name' => 'John')); - -// Retrieve the user by the attributes, or create it if it doesn't exist... -$user = User::firstOrCreate(array('name' => 'John')); - -// Retrieve the user by the attributes, or instantiate a new instance... -$user = User::firstOrNew(array('name' => 'John')); - -#### Model တစ်ခုအား Update ပြုလုပ်ခြင်း - -Model အား update ပြုလုပ်လိုပါက ရှေးဦးစွာ ပြုလုပ်လိုသည် record ကို retrieve ပြုလုပ်ရပါမည်။ ထိုနောက် attribute အား မိမိတို ့ထည့်သွင်းလိုသည့်နှင့် -ပြောင်းလဲ သတ်မှတ်ပြီး `save` method ကို အသုံးပြုကာ update ပြုလုပ်နိုင်ပါသည်။ - -$user = User::find(1); - -$user->email = 'john@foo.com'; - -$user->save(); - -#### Model နှင့် ၄င်း၏ Relationship များတွင် save ပြုလုပ်ခြင်း - -တခါတရံ သင့်အနေဖြင့် လက်ရှိ အသုံးပြုနေသည့် model တွင်သာ မက ၄င်းနှင့် relationship ပြုလုပ်ထားသော Model များတွင်ပါ save လုပ်လိုသည့် အခါများရှိပေမည်။ ထိုသို ့ ပြုလုပ်လိုပါက `push` method ကို အသုံးပြုနိုင်သည်။ - -$user->push(); - - -You may also run updates as queries against a set of models: - -$affectedRows = User::where('votes', '>', 100)->update(array('status' => 2)); - -> **Note:** No model events are fired when updating a set of models via the Eloquent query builder. - -#### Model မှ record များအား ဖျက်ပစ်ခြင်း - -record တစ်ခုအား ဖျက်ပစ်လိုပါက `delete` ဟုသော method ကို အသုံးပြုနိုင်သည်။ - -$user = User::find(1); - -$user->delete(); - -#### Model မှ record များအား key အလိုက် ဖျက်ပစ်ခြင်း - -User::destroy(1); - -User::destroy(array(1, 2, 3)); - -User::destroy(1, 2, 3); - -သင့်အနေဖြင့် query လုပ်ပြီးမှလည်း ဖျက်ပစ်နိုင်ပါသည်။ - -$affectedRows = User::where('votes', '>', 100)->delete(); - -#### Model ၏ Timestamps ကိုသာ update ပြုလုပ်ခြင်း - -Model ၏ Timestamps ကိုသာ update ပြုလုပ်လိုပါက `touch` ကို အသုံးပြုနိုင်သည်။ - -$user->touch(); - - -## Soft Deleting - -Soft delete ပြုလုပ်ပါက တကယ်ဖျက်ပစ်လိုက်ခြင်း မဟုတ်ပဲ သင့် record ထဲတွင် `deleted_at` ဟု timestamp တွင် သင့်ဖျက်ပစ်လိုက်သည့် အချိန်ကို မှတ်သားထားမည် ဖြစ်သည်။ Soft delete ကို ထည့်သွင်းလိုပါက `SoftDeletingTrait` ကိုပါ ထည့်သွင်းရမည် ဖြစ်သည်။ - -use Illuminate\Database\Eloquent\SoftDeletingTrait; - -class User extends Eloquent { - -use SoftDeletingTrait; - -protected $dates = ['deleted_at']; - -} - -`deleted_at` ဟုသည့် column ကို သင့်၏ table တွင် ထည့်သွင်းလိုပါက migration တွင် `softDeletes` ဟုသည့် method ကို အသုံးပြုနိုင်ပါသည်။ - -$table->softDeletes(); - -ထိုသို ့ပြုလုပ်ပြီး `delete` method ကို ခေါ်ယူပါက အမှန်တကယ် ဖျက်ပစ်မည် မဟုတ်ပဲ `deleted_at` ဟု column တွင် လက်ရှိ timestamp ကိုမှတ်သားထားမည် ဖြစ်သည်။ Model တစ်ခုတွင် soft delete ကို အသုံးပြုထားပါက query ပြုလုပ်သော အခါတိုင်းတွင် deleted record များမှာ ပါဝင်မည် မဟုတ်ပေ။ - -#### Soft Deleted record များပါ ရောစပ်ထုတ်ယူခြင်း - - -soft deleted record များပါ ပေါင်းစပ် ထုတ်ယူလိုပါက `withTrashed` ကို query တွင်ထည့်သွင်း အသုံးပြုရမည် ဖြစ်သည်။ - -$users = User::withTrashed()->where('account_id', 1)->get(); - -`withTrashed` method ကို relationship ပြုလုပ်ထားသော model တွင်လည်း အသုံးပြုနိုင်ပါသည်။ - -$user->posts()->withTrashed()->get(); - -ှSoft deleted ပြုလုပ်ထားသော results များသာ တွေ ့မြင်လိုပါက `onlyTrashed` ဟုသော method ကို အသုံးပြုနိုင်သည်။ - -$users = User::onlyTrashed()->where('account_id', 1)->get(); - -soft deleted ပြုလုပ်ထားသော record များကို restore ပြုလုပ်လိုပါက `restore` method ကို အသုံးပြုနိုင်သည်။ - -$user->restore(); - -`restore` method ကို query ပြုလုပ်နေသည့် အတောအတွင်းလည်း အသုံးပြုနိုင်သည်။ - -User::withTrashed()->where('account_id', 1)->restore(); - - -`withTrashed` ကဲ့သို ့ပင် `restore` method ကိုလည်း relationship များကြားထဲအတွင်း အသုံးပြုနိုင်သည်။ - -$user->posts()->restore(); - -Record တစ်ခုကို အမှန်တကယ် database ထဲမှ ဖျက်ပစ်လိုပါက `forceDelete` method ကို အသုံးပြုနိုင်သည်။ - -$user->forceDelete(); - -`forceDelete` method မှာလည်း relationship များအကြား အသုံးပြုနိုင်သည်။ - -$user->posts()->forceDelete(); - -soft delted ပြုလုပ်ထားခြင်း ဟုတ်မဟုတ် စစ်ဆေးနိုင်ရန် `trashed` method ကို အသုံးပြုနိုင်သည်။ - -if ($user->trashed()) -{ -// -} - - -## Timestamps - -ပုံမှန်အားဖြင့် Eloquent အနေဖြင့် `timestamp` attribute ကိုထည့်သွင်းပေးသည်နှင့် `created_at` and `updated_at` ကို အလိုအလျောက် ကိုင်တွယ်ပေးမည် ဖြစ်သည်။ သင့်အနေနှင့် မလိုချင်ပါက အောက်ပါအတိုင်း ပြောင်းလဲ သတ်မှတ်နိုင်သည်။ - -#### အလိုအလျောက် Timestamps ပြုလုပ်ခြင်းမှ ဖယ်ရှားခြင်း - -class User extends Eloquent { - -protected $table = 'users'; - -public $timestamps = false; - -} - -#### စိတ်ကြိုက် Timestamp တစ်ခုသတ်မှတ်ခြင်း - -Timestamp တစ်ခုကို စိတ်ကြိုက်သတ်မှတ်လိုပါက model အတွင်းရှိ `getDateFormat` ကို အသုံးပြု၍ သတ်မှတ်နိုင်သည်။ - -class User extends Eloquent { - -protected function getDateFormat() -{ -return 'U'; -} - -} - - -## Query Scopes - -#### Query Scope တစ်ခုအား သတ်မှတ်ခြင်း - -Scope များမှာ သင့်၏ query logic များကို ထပ်ခါထပ်ခါ အသုံးပြုနိုင်ခြင်း ဖြင့် သက်သာစေသည်။ Scope တစ်ခုကို ဖန်တီးနိုင်ရင် `scope` ဟုပါဝင်သည့် -method တစ်ခုကို ဖန်တီးရန် လိုပေမည်။ - -class User extends Eloquent { - -public function scopePopular($query) -{ -return $query->where('votes', '>', 100); -} - -public function scopeWomen($query) -{ -return $query->whereGender('W'); -} - -} - -#### Query Scope တစ်ခုအား အသုံးပြုခြင်း - -$users = User::popular()->women()->orderBy('created_at')->get(); - -#### Scopes အရှင်များ ဖန်တီးခြင်း - -တခါတရံ သင့်အနေဖြင့် parameter များလက်ခံသော scope အရှင်များကို ဖန်တီးလိုပေမည်။ ထိုသို ့ပြုလုပ်နိုင်ရန် သင့်၏ scope function အတွင်းတွင် - -class User extends Eloquent { - -public function scopeOfType($query, $type) -{ -return $query->whereType($type); -} - -} - -ထိုနောက် scope တွင် parameter ကို ထည့်သွင်း အသုံးပြုနိုင်သည်။ - -$users = User::ofType('member')->get(); - - -## Relationships - -Database table များမှာ တခါတရံ တစ်ခုနှင့် တစ်ခု ဆက်စပ်ပြီး တည်ရှိနိုင်ပေသည်။ ဥပမာ Blog post တစ်ခုတွင် comment များစွာ ပါဝင်သကဲ့သို ့ Order တစ်ခုတွင်လည်း User တစ်ယောက်နှင့် ဆက်စပ်နိုင် ပေသည်။ Laravel အနေဖြင့် ဆက်စပ်မှု မျိုးစုံကို ဆောင်ရွက်နိုင်အောင် ကူညီပေးထားပါသည်။ - -- [One To One](#one-to-one) -- [One To Many](#one-to-many) -- [Many To Many](#many-to-many) -- [Has Many Through](#has-many-through) -- [Polymorphic Relations](#polymorphic-relations) -- [Many To Many Polymorphic Relations](#many-to-many-polymorphic-relations) - - -### One To One - -#### One To One Relation တစ်ခုကို တည်ဆောက်ခြင်း - -one-to-one relationship မှာ အလွန်ပင် အခြေခံကျသော relation ဖြစ်သည်။ ဥပမာ User တစ်ယောက်တွင် Phone တစ်လုံး ရှိရမည့် အနေအထားမျိုး။ -ထိုသို ့သော relation မျိုးကို Eloquent တွင် ဖန်တီးနိုင်ပေသည်။ - -class User extends Eloquent { - -public function phone() -{ -return $this->hasOne('Phone'); -} - -} - - -`hasOne` တွင်ထည့်သွင်းရမည့် argument မှာ ဆက်စပ်နေသည့် Model ၏ အမည်ပင်ဖြစ်သည်။ relationship တည်ဆောက်ပြီးသည်နှင့် Eloquent ၏ [dynamic properties](#dynamic-properties): ကို အသုံးပြုပြီး အချက်အလက်များကို ထုတ်ယူနိုင်သည်။ - -$phone = User::find(1)->phone; - -အထက်ပါ statement အတွက် run သွားမည့် SQL မှာ အောက်ပါ အတိုင်းဖြစ်သည်။ - -select * from users where id = 1 - -select * from phones where user_id = 1 - -Eloquent အနေဖြင့် model name များကို အခြေခံပြီး Forigen key များကို သတ်မှတ်သွားမည်ကို သတိပြုရမည်။ အထက်က `Phone` model တွင် `user_id` ကို foreign key အနေဖြင့် အလိုအလျောက် သတ်မှတ်မည် ဖြစ်သည်။ မိမိတို ့ စိတ်ကြိုက်ပြောင်းလဲလိုပါက `hasOne` method တွင် ဒုတိယ argument အဖြစ်သွင်းပေးရန် လိုပေမည်။ ထိုထက်ပို၍ တတိယ argument အနေဖြင့် ထည့်သွင်းပါက မည်သည့် local column ကို ပူးပေါင်းမည်ကိုပါ သတ်မှတ်နိုင်သည်။ + class Flight extends Model + { + /** + * The connection name for the model. + * + * @var string + */ + protected $connection = 'connection-name'; + } -return $this->hasOne('Phone', 'foreign_key'); + +## Retrieving Models -return $this->hasOne('Phone', 'foreign_key', 'local_key'); +Once you have created a model and [its associated database table](/docs/{{version}}/migrations#writing-migrations), you are ready to start retrieving data from your database. Think of each Eloquent model as a powerful [query builder](/docs/{{version}}/queries) allowing you to fluently query the database table associated with the model. For example: -#### Relation ပြောင်းပြန်သတ်မှတ်ခြင်း + belongsTo('User'); -} + foreach ($flights as $flight) { + echo $flight->name; + } -} +#### Adding Additional Constraints -အထက်က ဥပမာတွင် Eloquent အနေဖြင့် `phones` table မှ `user_id` column ကို အသုံးပြုမည် ဖြစ်သည်။ `hasMany` ကဲ့သို ့ပင် Foriegn Key ကို သတ်မှတ်လိုပါက ဒုတိယ argument ကို ထည့်သွင်းပေးနိုင်သည်။ +The Eloquent `all` method will return all of the results in the model's table. Since each Eloquent model serves as a [query builder](/docs/{{version}}/queries), you may also add constraints to queries, and then use the `get` method to retrieve the results: + $flights = App\Flight::where('active', 1) + ->orderBy('name', 'desc') + ->take(10) + ->get(); -class Phone extends Eloquent { +> {tip} Since Eloquent models are query builders, you should review all of the methods available on the [query builder](/docs/{{version}}/queries). You may use any of these methods in your Eloquent queries. -public function user() -{ -return $this->belongsTo('User', 'local_key'); -} - -} - -ထိုအပြင် parent table နှင့်ဆက်စပ်နေသည့် column ကို တတိယ parameter အဖြစ် ထည့်သွင်းနိုင်သည်။ - -class Phone extends Eloquent { - -public function user() -{ -return $this->belongsTo('User', 'local_key', 'parent_key'); -} - -} - - -### One To Many - -one-to-many relation ၏ ဥပမာမှာ blog post တစ်ခုတွင် comment များစွာ ရှိသကဲ့သို ့ပင် ဖြစ်သည်။ ထိုသို ့ relation ကို အောက်ပါအတိုင်း model တွင် -သတ်မှတ်နိုင်သည်။ - -class Post extends Eloquent { - -public function comments() -{ -return $this->hasMany('Comment'); -} - -} - -ထိုအခါ post comments များကို [dynamic property](#dynamic-properties) ကို အသုံးပြု၍ ထုတ်ယူနိုင်ပါပြီ။ - -$comments = Post::find(1)->comments; - -ထိုထဲမှ ထုတ်ယူလိုသည့် comment များကို စစ်ယူလိုပါက `comments` method နောက်တွင် method များကို စီတန်း အသုံးပြုနိုင်ပါသေးသည်။ - -$comments = Post::find(1)->comments()->where('title', '=', 'foo')->first(); - -၄င်းတွင်လည်း `hasOne` ကဲ့သို ့ foriegn key ကို `hasMany` method နောက်တွင် second argument အနေဖြင့်နှင့် third argument ကို local key အနေဖြင့် ထည့်သွင်းနိုင်ပေသည်။ - -return $this->hasMany('Comment', 'foreign_key'); - -return $this->hasMany('Comment', 'foreign_key', 'local_key'); - -#### ပြောင်းပြန် relation သတ်မှတ်ခြင်း - -`Comment` model ပြောင်းပြန် သတ်မှတ်နိုင်ရန် `belongsTo` ဟုသည့် method ကို အသုံးပြုနိုင်သည်။ - -class Comment extends Eloquent { - -public function post() -{ -return $this->belongsTo('Post'); -} - -} - - -### Many To Many - - -Many-to-many relations မှာ ပိုမိုရှုပ်ထွေးသည့် relation ဖြစ်သည်။ ဥပမာ User တစ်ယောက်မှာ တာဝန်များစွာ ရှိပြီး တာဝန်တစ်ခုကိုလည်း User များစွာ ခွဲဝေပေးအပ်ထားသည် ဆိုပါစို ့။ User များစွာ "Admin" တာဝန်ကို ယူထားနိုင်သည့် အခြေအနေတွင်ရှိပေမည်။ ထိုသို ့သော အခြေအနေတွင် Database -Table သုံးခု လိုအပ်မည် ဖြစ်သည်။ ၄င်းတို ့မှာ `users` ၊ `roles` နှင့် `role_user` တို ့ဖြစ်ကြသည်။ `role_user` table မှာ ဆက်စပ်နေသည့် model အမည်များကို ဆက်စပ်ပေးမည် ဖြစ်ပြီး ၄င်းတွင် `user_id` နှင့် `role_id` ဟူသော columns နှစ်ခု ပါဝင်မည် ဖြစ်သည်။ - - -many-to-many relation ကို `belongsToMany` method ကို အသုံးပြု၍ ရေးသားနိုင်သည်။ - -class User extends Eloquent { - -public function roles() -{ -return $this->belongsToMany('Role'); -} - -} - -ထိုအခါ `User` မှ role ကို အောက်ပါ အတိုင်း ထုတ်ယူနိုင်မည် ဖြစ်သည်။ - -$roles = User::find(1)->roles; - -မိမိ၏ ကြားခံ table ၏ အမည်ကို စိတ်ကြိုက် သတ်မှတ်လိုပါက `belongsToMany` method ၏ ဒုတိယ argument မှ သွင်း၍ စိတ်ကြိုက် သတ်မှတ်နိုင်သည်။ - -return $this->belongsToMany('Role', 'user_roles'); - -ထိုအပြင် ပါဝင်ပတ်သတ်နေသော Keys များကိုလည်း စိတ်ကြိုက် သတ်မှတ်နိုင်သည်။ - -return $this->belongsToMany('Role', 'user_roles', 'user_id', 'foo_id'); - -ထိုအပြင် `Role` model မှလည်း ပြောင်းပြန်သတ်မှတ် ၍လည်း ဖြစ်ပါသည်။ - -class Role extends Eloquent { - -public function users() -{ -return $this->belongsToMany('User'); -} - -} - - -### Has Many Through - - "has many through" ဝေးကွာနေသည့် relation များမှ record များကို access လုပ်နိုင်ရန် အလွယ်တကူ ကြားဖြတ်ဆောင်ရွက်ပေးသော method ဇြစ်သည်။ ဥပမာ `Country` model မှာ `Posts` ဖြင့် ချိတ်ဆက်ထားခြင်း မရှိသော်လည်း `Users` model ဖြင့်မူ ချိတ်ဆက်ထားပါက တဆင့်ကျော်၍ access လုပ်နိုင်သည်။ ထို table များ၏ relationship မှာ အောက်ပါအတိုင်း ဆိုပါစို ့ - -countries -id - integer -name - string - -users -id - integer -country_id - integer -name - string - -posts -id - integer -user_id - integer -title - string - -`posts` table တွင် `country_id` column မပါဝင်သော်လည်း `hasManyThrough` relation ဖြင့် `$country->posts` ဟု၍ accessible ဖြစ်အောင် စွမ်းဆောင်နိုင်ပေသည်။ - -class Country extends Eloquent { - -public function posts() -{ -return $this->hasManyThrough('Post', 'User'); -} - -} - -relationship key များကို စိတ်ကြိုက်သတ်မှတ်လိုပါက တတိယနှင့် စတုတ္ထ parameter အများအဖြစ် ထည့်သွင်းနိုင်ပေသည်။ - -class Country extends Eloquent { - -public function posts() -{ -return $this->hasManyThrough('Post', 'User', 'country_id', 'user_id'); -} - -} - - -### Polymorphic Relations - -Polymorphic relations ကို အသုံးပြုခြင်းဖြင့် အခြား Model တစ်ခုထက်ပို၍ associate ပြုလုပ်ထားသော record များကို ထုတ်ယူနိုင်သည်။ ဥပမာ သင့်တွင် -staff ဟုသော model နှင့် order ဟုသော model နှစ်ခုလုံးနှင့် ပတ်သတ်နေသည့် photo ဟုသော model ရှိသည် ဆိုပါစို ့။ - - -class Photo extends Eloquent { - -public function imageable() -{ -return $this->morphTo(); -} - -} - -class Staff extends Eloquent { - -public function photos() -{ -return $this->morphMany('Photo', 'imageable'); -} - -} - -class Order extends Eloquent { - -public function photos() -{ -return $this->morphMany('Photo', 'imageable'); -} - -} - -#### Polymorphic Relation ကို အသုံးပြုခြင်း - -အောက်ပါ အတိုင်း photo များကို Staff member များမှသော်လည်းကောင်း Order မှသော်လည်းကောင်း ထုတ်ယူနိုင်သည်။ - -$staff = Staff::find(1); - -foreach ($staff->photos as $photo) -{ -// -} - -#### Polymorphic Relation မှ Owner ၏ record များကို ထုတ်ယူခြင်း - -သို ့သော် တကယ့် "polymorphic" အလှတရားမှာ `Photo` model မှ staff ဖြစ်စေ ၊ order ဖြစ်စေ ထုတ်ယူနိုင်ခြင်း ဖြစ်သည်။ - - -$photo = Photo::find(1); - -$imageable = $photo->imageable; - -`Photo` model မှ `imageable` relation မှာ `Staff` မှဖြစ်စေ `Order` instance ဖြစ်စေ ပိုင်ဆိုင်သည့် model ပေါ်မူတည်၍ ထုတ်ပေးသွားမည် ဖြစ်သည်။ - -#### Polymorphic Relation Table Structure - -မည်သို ့မည်ပုံ အလုပ်လုပ်ဆောင်သွားသည်ကို သိရှိနိုင်ရန် အောက်ပါ database structure ကို ကြည့်ရှုနိုင်ပါသည်။ - -staff -id - integer -name - string - -orders -id - integer -price - integer - -photos -id - integer -path - string -imageable_id - integer -imageable_type - string - -Key field အနေဖြင့် `photos` table မှ `imageable_id` နှင့် `imageable_type` တို ့ကို မှတ်သားထားရပါမည် ဖြစ်သည်။ ID မှာ Order သို ့မဟုတ် -Staff တို ့၏ ID နှင့် ချိတ်ဆက်ထားမည် ဖြစ်သည်။ ORM အနေဖြင့် မည်သည့် model ကိုပြန်ရမည် ဆိုသည်ကို `imageable` ၏ relation ကို ထောက်ရှု၍ လုပ်ဆောင် သွားမည် ဖြစ်သည်။ - - -### Many To Many Polymorphic Relations - -#### Polymorphic Many To Many Relation Table Structure - -သမရိုးကျ polymorphic relations တစ်ခုသာမက many-to-many polymorphic relations များကိုပါ တည်ဆောက်နိုင်သည်။ ဥပမာ blog တစ်ခု၏ database structure ဖြစ်သော `Post` နှင့် `Video` model တို ့တွင် `Tag` model ကို တူညီစွာ polymorphic relation အနေဖြင့် ချိတ်ဆက်ရန် လိုပေမည်။ ရှေဦးစွာ table structure ကိုကြည့်လိုက်ပါ။ - -posts -id - integer -name - string - -videos -id - integer -name - string - -tags -id - integer -name - string - -taggables -tag_id - integer -taggable_id - integer -taggable_type - string - -အထက်ပါ table အတွက် relationship များကို model တွင် အောက်ပါအတိုင်း တည်ဆောက်ရမည်ဖြစ်သည်။ `Post` နှင့် `Video` model တို ့နှစ်ခုလုံးတွင် -`tags` method မှ `morphToMany` relationship ကို ကြေညာပေးရမည် ဖြစ်သည်။ - -class Post extends Eloquent { - -public function tags() -{ -return $this->morphToMany('Tag', 'taggable'); -} - -} - -`Tag` model အနေဖြင့် ၄င်း၏ relationships ကို အောက်ပါ အတိုင်း သတ်မှတ်နိုင်သည်။ - -class Tag extends Eloquent { - -public function posts() -{ -return $this->morphedByMany('Post', 'taggable'); -} - -public function videos() -{ -return $this->morphedByMany('Video', 'taggable'); -} - -} - - -## Relation များကို Query ပြုလုပ်ခြင်း - -#### Relations များတွင် Select ကို အသုံးပြုခြင်း - -Model များမှ record များကို access ပြုလုပ်ရာတွင် ၊ result များကို စစ်ဆေးပြီးမှ ထုတ်ယူလိုသည့် အနေအထားမျိုးတွင် ရှိပေနိုင်သည်။ ဥပမာ သင့်အနေဖြင့် Comment တစ်ခု အနည်းဆုံး ရှိသည့် blog post များကို ဆွဲထုတ်လိုသည် ဆိုပါစို ့။ သင့်အနေနဲ ့ `has` method ကို အသုံးပြုရမည် ဖြစ်သည်။ - -$posts = Post::has('comments')->get(); - -has method တွင် သင့်အနေဖြင့် operator များ နှင့် ထုတ်ယူလိုသည့် အရေအတွက်ကို သတ်မှတ်နိုင်သည်။ - -$posts = Post::has('comments', '>=', 3)->get(); - -သင့်အနေဖြင့် ပို၍ အသေးစိတ်ကျပြီး "where" conditions များကို `has` queries အတွင်း စစ်ဆေးလိုပါက `whereHas` နှင့် `orWhereHas` method များကိုအသုံးပြုနိုင်သည်။ - -$posts = Post::whereHas('comments', function($q) -{ -$q->where('content', 'like', 'foo%'); - -})->get(); - - -### Dynamic Properties - - -Eloquent တွင် သင့်အနေဖြင့် relations များမှ properties များကို dynamic properties အနေဖြင့် ဆွဲယူနိုင်သည်။ Eloquent အနေဖြင့် သင့်၏ relationship အလိုအလျောက်အနေဖြင့် relations ကို အလိုအလျောက် load လုပ်ကာ ခေါ်ယူမည် ဖြစ်ပြီး `get` ( one-to-many relationships) ပေလော၊ `first` (for one-to-one relationships) method ပေလော ကိုပင် ခွဲခြားလုပ်ဆောင်ပေးမည် ဖြစ်သည်။ ထိုနောက် တူညီသော အမည်မှ တဆင့် -dynamic property ကို အလွယ်တကူ ခေါ်ဆို နိုင်ပေမည်။ ဥပမာ `$phone` ဟုသည့် model မှ တဆင့် - -class Phone extends Eloquent { - -public function user() -{ -return $this->belongsTo('User'); -} - -} - -$phone = Phone::find(1); - -Instead of echoing the user's email like this: - -echo $phone->user()->first()->email; - -It may be shortened to simply: - -echo $phone->user->email; - -> **Note:** Relationships များကို return ပြန်သော result များကို အလုပ်လုပ်သွားသော method မှာ `Illuminate\Database\Eloquent\Collection` class မှ instance များကို ပြန်ခြင်းဖြစ်သည်။ - - -## Eager Loading - - -Eager loading exists to N+1 query ကဲ့သို ့သော Query များကို ပို ့၍ ပေါ့ပါးစွာ အသုံးပြုနိုင်ရန် ဖြစ်သည်။ ဥပမာ `Author` model နှင့် `Book` model တို ့ ဆက်စပ်နေသည် ဆိုပါစို ့။ ၄င်းတို ့၏ relationship ကို အောက်ပါ အတိုင်း သတ်မှတ်နိုင်ပါသည်။ - -class Book extends Eloquent { - -public function author() -{ -return $this->belongsTo('Author'); -} - -} - -ထိုနောက် အောက်ပါ code ကို ကြည့်ကြည့်ပါ။ - -foreach (Book::all() as $book) -{ -echo $book->author->name; -} - -ထို loop မှာ Book မှ ရှိသမျှ စာအုပ်တိုင်းကို ခေါ်ယူမည် ဖြစ်သည်။ ထိုနောက် ထိုနောက် ထိုနောက် နောက် query တစ်ခုအနေဖြင့် စာအုပ်တစ်ခုချင်းဆီ၏ -author ကို ဖော်ပြသွားမည် ဖြစ်သည်။ အကယ်၍ စာအုပ် ၂၅ အုပ် ရှိသည် ဆိုပါစို ့ ၊ query ၂၆ ကြောင်း run ဖြစ်သည်။ သို ့ပင်သော်ညား eager loading ၏ အကျိုးကျေးဇူးကြောင့် မလိုအပ်သော query များကို လျှော့ချနိုင်သည်။ ထို relationship တွင် `with` method အသုံးပြု၍ eager load ပြုလုပ်နိုင်သည်။ - - -foreach (Book::with('author')->get() as $book) -{ -echo $book->author->name; -} - -အထက်ပါ loop တွင်မူ query နှစ်ကြောင်းသာ execute ပြုလုပ်မည် ဖြစ်သည်။ - -select * from books - -select * from authors where id in (1, 2, 3, 4, 5, ...) - -Eager loading ကို အသုံးပြုခြင်း အားဖြင့် သင့် application ၏ performance ကို သိသိသာသာ မြင့်တက်စေမည် ဖြစ်သည်။ - -ထိုအပြင် တစ်ခုထက်ပိုသော relation များတွင် တချိန်တည်းတွင် eager load အသုံးပြုနိုင်မည် ဖြစ်သည်။ - -$books = Book::with('author', 'publisher')->get(); + +### Collections -Nested relationship များတွင်လည်း eager load အသုံးပြုနိုင်သည်။ +For Eloquent methods like `all` and `get` which retrieve multiple results, an instance of `Illuminate\Database\Eloquent\Collection` will be returned. The `Collection` class provides [a variety of helpful methods](/docs/{{version}}/eloquent-collections#available-methods) for working with your Eloquent results: -$books = Book::with('author.contacts')->get(); + $flights = $flights->reject(function ($flight) { + return $flight->cancelled; + }); -အထက် ဥပမာ တွင် `author` နှင့် ပတ်သတ်နေသည်များကို eager load ပြုလုပ်ပြီး author ၏ `contacts` relation ပါ load သွားမည် ဖြစ်သည်။ +Of course, you may also simply loop over the collection like an array: -### Eager Load အကန် ့အသတ်များ + foreach ($flights as $flight) { + echo $flight->name; + } -ထခါတရံ condition များ စစ်ဆေးပြီးမှ relationship များကို eager load ပြုလုပ်လိုမည် အချိန်ကာလ လည်း ရှိပေမည်။ အောက်က ဥပမာတွင် ဆိုပါစို ့ + +### Chunking Results -$users = User::with(array('posts' => function($query) -{ -$query->where('title', 'like', '%first%'); +If you need to process thousands of Eloquent records, use the `chunk` command. The `chunk` method will retrieve a "chunk" of Eloquent models, feeding them to a given `Closure` for processing. Using the `chunk` method will conserve memory when working with large result sets: -}))->get(); + Flight::chunk(200, function ($flights) { + foreach ($flights as $flight) { + // + } + }); -ထို ဥပမာ တွင် user's post တွင်းမှ "first" စကာလုံး နှင့်စတင်သည်များကိုသာ eager load လုပ်သွားမည် ဖြစ်သည်။ Closure များ အတွင်းတွင်မူ အကန့် အသတ်မရှိပေ။ သင့်အနေဖြင့် အောက်က အတိုင်း order အလိုက် စီရီနိုင်ပေဦးမည်။ +The first argument passed to the method is the number of records you wish to receive per "chunk". The Closure passed as the second argument will be called for each chunk that is retrieved from the database. A database query will be executed to retrieve each chunk of records passed to the Closure. -$users = User::with(array('posts' => function($query) -{ -$query->orderBy('created_at', 'desc'); +#### Using Cursors -}))->get(); +The `cursor` method allows you to iterate through your database records using a cursor, which will only execute a single query. When processing large amounts of data, the `cursor` method may be used to greatly reduce your memory usage: -### Lazy Eager Loading + foreach (Flight::where('foo', 'bar')->cursor() as $flight) { + // + } -တည်ရှိနေပြီးသော model collection များထဲမှ eager load နှင့် ဆက်စပ်နေသော model များကို တိုက်ရိုက် ခေါ်ယူ၍လည်း ဖြစ်နိုင်ပေသည်။ ထိုသို ့ပြုလုပ်ခြင်း Model များကို Load လုပ်ရာတွင် load လုပ်မည် မလုပ်မည်ကို dynamically စဉ်းစားဆုံးဖြတ်ရာတွင် သော်လည်းကောင်း ၊ caching ဖြင့် ပူးပေါင်း အသုံးပြုရာတွင်သော်လည်းကောင်း အသုံးဝင်သည်။ + +## Retrieving Single Models / Aggregates -$books = Book::all(); +Of course, in addition to retrieving all of the records for a given table, you may also retrieve single records using `find` and `first`. Instead of returning a collection of models, these methods return a single model instance: -$books->load('author', 'publisher'); + // Retrieve a model by its primary key... + $flight = App\Flight::find(1); - -## ဆက်စပ်နေသည့် Model များတွင် data ထည့်သွင်းခြင်း + // Retrieve the first model matching the query constraints... + $flight = App\Flight::where('active', 1)->first(); -#### ဆက်စပ်နေသည့် Model ဖြင့် ချိတ်ဆက်ခြင်း +You may also call the `find` method with an array of primary keys, which will return a collection of the matching records: -တခါတရံ ဆက်စပ်နေသည့် model များအား insert ပြုလုပ်ရန်လည်း လိုပေမည်။ ဥပမာ သင့်အနေဖြင့် post တစ်ခုတွင် comment တစ်ခုကို ထည့်သွင်းမည် ဆိုပါစို ့။ Model တစ်ခု၏ `post_id` foreign key ကို manually ထည့်သွင်းနေမည့် အစား `Post` model ဖက်မှ တိုက်ရိုက်ထည့်သွင်း၍လည်း ရပေသည်။ + $flights = App\Flight::find([1, 2, 3]); -$comment = new Comment(array('message' => 'A new comment.')); +#### Not Found Exceptions -$post = Post::find(1); +Sometimes you may wish to throw an exception if a model is not found. This is particularly useful in routes or controllers. The `findOrFail` and `firstOrFail` methods will retrieve the first result of the query; however, if no result is found, a `Illuminate\Database\Eloquent\ModelNotFoundException` will be thrown: -$comment = $post->comments()->save($comment); + $model = App\Flight::findOrFail(1); -အထက်က ဥပမာတွင် `post_id` field ကို အလိုအလျောက် ထည့်သွင်းသွားမည် ဖြစ်သည်။ + $model = App\Flight::where('legs', '>', 100)->firstOrFail(); -### Models များ ဆက်စပ်ခြင်း(Belongs To) +If the exception is not caught, a `404` HTTP response is automatically sent back to the user. It is not necessary to write explicit checks to return `404` responses when using these methods: -`belongsTo` relationship ဖြင့် Method များကို data များ update လုပ်စေလိုပါက `associate` method ကို အသုံးပြုနိုင်သည်။ ထို method သည် လက်အောက်ခံ model ၏ foregin key ကိုပါ ထည့်သွင်းပေးသွားမည် ဖြစ်သည်။ + Route::get('/api/flights/{id}', function ($id) { + return App\Flight::findOrFail($id); + }); -$account = Account::find(10); + +### Retrieving Aggregates -$user->account()->associate($account); +You may also use the `count`, `sum`, `max`, and other [aggregate methods](/docs/{{version}}/queries#aggregates) provided by the [query builder](/docs/{{version}}/queries). These methods return the appropriate scalar value instead of a full model instance: -$user->save(); + $count = App\Flight::where('active', 1)->count(); -### ဆက်စပ်နေသည့် Model တွင် data ထည့်သွင်းခြင်း (Many To Many) + $max = App\Flight::where('active', 1)->max('price'); -သင့်အနေဖြင့် many-to-many relations ရှိနေသည့် model များတွင်လည်း data ဖြည့်သွင်းလိုပေမည်။ ထုံးစံ ဥပမာ တစ်ခုဖြစ်သည့် `User` နှင့် `Role` model များဖြင့် ရှေ ့ဆက်ကြစို ့။ user ၏ roles များကို `attach` method ဖြင့် ချိတ်ဆက်နိုင်သည်။ + +## Inserting & Updating Models -#### Attaching Many To Many Models + +### Inserts -$user = User::find(1); +To create a new record in the database, simply create a new model instance, set attributes on the model, then call the `save` method: -$user->roles()->attach(1); + roles()->attach(1, array('expires' => $expires)); + use App\Flight; + use Illuminate\Http\Request; + use App\Http\Controllers\Controller; -Of course, the opposite of `attach` is `detach`: + class FlightController extends Controller + { + /** + * Create a new flight instance. + * + * @param Request $request + * @return Response + */ + public function store(Request $request) + { + // Validate the request... -$user->roles()->detach(1); + $flight = new Flight; -#### Using Sync To Attach Many To Many Models + $flight->name = $request->name; -You may also use the `sync` method to attach related models. The `sync` method accepts an array of IDs to place on the pivot table. After this operation is complete, only the IDs in the array will be on the intermediate table for the model: + $flight->save(); + } + } -$user->roles()->sync(array(1, 2, 3)); +In this example, we simply assign the `name` parameter from the incoming HTTP request to the `name` attribute of the `App\Flight` model instance. When we call the `save` method, a record will be inserted into the database. The `created_at` and `updated_at` timestamps will automatically be set when the `save` method is called, so there is no need to set them manually. -#### Adding Pivot Data When Syncing + +### Updates -You may also associate other pivot table values with the given IDs: +The `save` method may also be used to update models that already exist in the database. To update a model, you should retrieve it, set any attributes you wish to update, and then call the `save` method. Again, the `updated_at` timestamp will automatically be updated, so there is no need to manually set its value: -$user->roles()->sync(array(1 => array('expires' => true))); + $flight = App\Flight::find(1); -Sometimes you may wish to create a new related model and attach it in a single command. For this operation, you may use the `save` method: + $flight->name = 'New Flight Name'; -$role = new Role(array('name' => 'Editor')); + $flight->save(); -User::find(1)->roles()->save($role); +#### Mass Updates -In this example, the new `Role` model will be saved and attached to the user model. You may also pass an array of attributes to place on the joining table for this operation: +Updates can also be performed against any number of models that match a given query. In this example, all flights that are `active` and have a `destination` of `San Diego` will be marked as delayed: -User::find(1)->roles()->save($role, array('expires' => $expires)); + App\Flight::where('active', 1) + ->where('destination', 'San Diego') + ->update(['delayed' => 1]); - -## Touching Parent Timestamps +The `update` method expects an array of column and value pairs representing the columns that should be updated. -When a model `belongsTo` another model, such as a `Comment` which belongs to a `Post`, it is often helpful to update the parent's timestamp when the child model is updated. For example, when a `Comment` model is updated, you may want to automatically touch the `updated_at` timestamp of the owning `Post`. Eloquent makes it easy. Just add a `touches` property containing the names of the relationships to the child model: +> {note} When issuing a mass update via Eloquent, the `saved` and `updated` model events will not be fired for the updated models. This is because the models are never actually retrieved when issuing a mass update. -class Comment extends Eloquent { + +### Mass Assignment -protected $touches = array('post'); +You may also use the `create` method to save a new model in a single line. The inserted model instance will be returned to you from the method. However, before doing so, you will need to specify either a `fillable` or `guarded` attribute on the model, as all Eloquent models protect against mass-assignment by default. -public function post() -{ -return $this->belongsTo('Post'); -} +A mass-assignment vulnerability occurs when a user passes an unexpected HTTP parameter through a request, and that parameter changes a column in your database you did not expect. For example, a malicious user might send an `is_admin` parameter through an HTTP request, which is then passed into your model's `create` method, allowing the user to escalate themselves to an administrator. -} +So, to get started, you should define which model attributes you want to make mass assignable. You may do this using the `$fillable` property on the model. For example, let's make the `name` attribute of our `Flight` model mass assignable: -Now, when you update a `Comment`, the owning `Post` will have its `updated_at` column updated: + text = 'Edit to this comment!'; + use Illuminate\Database\Eloquent\Model; -$comment->save(); + class Flight extends Model + { + /** + * The attributes that are mass assignable. + * + * @var array + */ + protected $fillable = ['name']; + } - -## Working With Pivot Tables +Once we have made the attributes mass assignable, we can use the `create` method to insert a new record in the database. The `create` method returns the saved model instance: -As you have already learned, working with many-to-many relations requires the presence of an intermediate table. Eloquent provides some very helpful ways of interacting with this table. For example, let's assume our `User` object has many `Role` objects that it is related to. After accessing this relationship, we may access the `pivot` table on the models: + $flight = App\Flight::create(['name' => 'Flight 10']); -$user = User::find(1); +If you already have a model instance, you may use the `fill` method to populate it with an array of attributes: -foreach ($user->roles as $role) -{ -echo $role->pivot->created_at; -} + $flight->fill(['name' => 'Flight 22']); -Notice that each `Role` model we retrieve is automatically assigned a `pivot` attribute. This attribute contains a model representing the intermediate table, and may be used as any other Eloquent model. +#### Guarding Attributes -By default, only the keys will be present on the `pivot` object. If your pivot table contains extra attributes, you must specify them when defining the relationship: +While `$fillable` serves as a "white list" of attributes that should be mass assignable, you may also choose to use `$guarded`. The `$guarded` property should contain an array of attributes that you do not want to be mass assignable. All other attributes not in the array will be mass assignable. So, `$guarded` functions like a "black list". Of course, you should use either `$fillable` or `$guarded` - not both. In the example below, all attributes **except for `price`** will be mass assignable: -return $this->belongsToMany('Role')->withPivot('foo', 'bar'); + belongsToMany('Role')->withTimestamps(); + class Flight extends Model + { + /** + * The attributes that aren't mass assignable. + * + * @var array + */ + protected $guarded = ['price']; + } -#### Deleting Records On A Pivot Table +If you would like to make all attributes mass assignable, you may define the `$guarded` property as an empty array: -To delete all records on the pivot table for a model, you may use the `detach` method: + /** + * The attributes that aren't mass assignable. + * + * @var array + */ + protected $guarded = []; -User::find(1)->roles()->detach(); + +### Other Creation Methods -Note that this operation does not delete records from the `roles` table, but only from the pivot table. +#### `firstOrCreate`/ `firstOrNew` -#### Updating A Record On A Pivot Table +There are two other methods you may use to create models by mass assigning attributes: `firstOrCreate` and `firstOrNew`. The `firstOrCreate` method will attempt to locate a database record using the given column / value pairs. If the model can not be found in the database, a record will be inserted with the given attributes. -Sometimes you may need to update your pivot table, but not detach it. If you wish to update your pivot table in place you may use `updateExistingPivot` method like so: +The `firstOrNew` method, like `firstOrCreate` will attempt to locate a record in the database matching the given attributes. However, if a model is not found, a new model instance will be returned. Note that the model returned by `firstOrNew` has not yet been persisted to the database. You will need to call `save` manually to persist it: -User::find(1)->roles()->updateExistingPivot($roleId, $attributes); + // Retrieve the flight by the attributes, or create it if it doesn't exist... + $flight = App\Flight::firstOrCreate(['name' => 'Flight 10']); -#### Defining A Custom Pivot Model + // Retrieve the flight by the attributes, or instantiate a new instance... + $flight = App\Flight::firstOrNew(['name' => 'Flight 10']); -Laravel also allows you to define a custom Pivot model. To define a custom model, first create your own "Base" model class that extends `Eloquent`. In your other Eloquent models, extend this custom base model instead of the default `Eloquent` base. In your base model, add the following function that returns an instance of your custom Pivot model: +#### `updateOrCreate` -public function newPivot(Model $parent, array $attributes, $table, $exists) -{ -return new YourCustomPivot($parent, $attributes, $table, $exists); -} +You may also come across situations where you want to update an existing model or create a new model if none exists. Laravel provides an `updateOrCreate` method to do this in one step. Like the `firstOrCreate` method, `updateOrCreate` persists the model, so there's no need to call `save()`: - -## Collections + // If there's a flight from Oakland to San Diego, set the price to $99. + // If no matching model exists, create one. + $flight = App\Flight::updateOrCreate( + ['departure' => 'Oakland', 'destination' => 'San Diego'], + ['price' => 99] + ); -All multi-result sets returned by Eloquent, either via the `get` method or a `relationship`, will return a collection object. This object implements the `IteratorAggregate` PHP interface so it can be iterated over like an array. However, this object also has a variety of other helpful methods for working with result sets. + +## Deleting Models -#### Checking If A Collection Contains A Key +To delete a model, call the `delete` method on a model instance: -For example, we may determine if a result set contains a given primary key using the `contains` method: + $flight = App\Flight::find(1); -$roles = User::find(1)->roles; + $flight->delete(); -if ($roles->contains(2)) -{ -// -} +#### Deleting An Existing Model By Key -Collections may also be converted to an array or JSON: +In the example above, we are retrieving the model from the database before calling the `delete` method. However, if you know the primary key of the model, you may delete the model without retrieving it. To do so, call the `destroy` method: -$roles = User::find(1)->roles->toArray(); + App\Flight::destroy(1); -$roles = User::find(1)->roles->toJson(); + App\Flight::destroy([1, 2, 3]); -If a collection is cast to a string, it will be returned as JSON: + App\Flight::destroy(1, 2, 3); -$roles = (string) User::find(1)->roles; +#### Deleting Models By Query -#### Iterating Collections +Of course, you may also run a delete statement on a set of models. In this example, we will delete all flights that are marked as inactive. Like mass updates, mass deletes will not fire any model events for the models that are deleted: -Eloquent collections also contain a few helpful methods for looping and filtering the items they contain: + $deletedRows = App\Flight::where('active', 0)->delete(); -$roles = $user->roles->each(function($role) -{ -// -}); +> {note} When executing a mass delete statement via Eloquent, the `deleting` and `deleted` model events will not be fired for the deleted models. This is because the models are never actually retrieved when executing the delete statement. -#### Filtering Collections + +### Soft Deleting -When filtering collections, the callback provided will be used as callback for [array_filter](http://php.net/manual/en/function.array-filter.php). +In addition to actually removing records from your database, Eloquent can also "soft delete" models. When models are soft deleted, they are not actually removed from your database. Instead, a `deleted_at` attribute is set on the model and inserted into the database. If a model has a non-null `deleted_at` value, the model has been soft deleted. To enable soft deletes for a model, use the `Illuminate\Database\Eloquent\SoftDeletes` trait on the model and add the `deleted_at` column to your `$dates` property: -$users = $users->filter(function($user) -{ -return $user->isAdmin(); -}); + **Note:** When filtering a collection and converting it to JSON, try calling the `values` function first to reset the array's keys. + namespace App; -#### Applying A Callback To Each Collection Object + use Illuminate\Database\Eloquent\Model; + use Illuminate\Database\Eloquent\SoftDeletes; -$roles = User::find(1)->roles; + class Flight extends Model + { + use SoftDeletes; -$roles->each(function($role) -{ -// -}); + /** + * The attributes that should be mutated to dates. + * + * @var array + */ + protected $dates = ['deleted_at']; + } -#### Sorting A Collection By A Value +Of course, you should add the `deleted_at` column to your database table. The Laravel [schema builder](/docs/{{version}}/migrations) contains a helper method to create this column: -$roles = $roles->sortBy(function($role) -{ -return $role->created_at; -}); + Schema::table('flights', function ($table) { + $table->softDeletes(); + }); -#### Sorting A Collection By A Value +Now, when you call the `delete` method on the model, the `deleted_at` column will be set to the current date and time. And, when querying a model that uses soft deletes, the soft deleted models will automatically be excluded from all query results. -$roles = $roles->sortBy('created_at'); +To determine if a given model instance has been soft deleted, use the `trashed` method: -#### Returning A Custom Collection Type + if ($flight->trashed()) { + // + } -Sometimes, you may wish to return a custom Collection object with your own added methods. You may specify this on your Eloquent model by overriding the `newCollection` method: + +### Querying Soft Deleted Models -class User extends Eloquent { +#### Including Soft Deleted Models -public function newCollection(array $models = array()) -{ -return new CustomCollection($models); -} +As noted above, soft deleted models will automatically be excluded from query results. However, you may force soft deleted models to appear in a result set using the `withTrashed` method on the query: -} + $flights = App\Flight::withTrashed() + ->where('account_id', 1) + ->get(); - -## Accessors & Mutators +The `withTrashed` method may also be used on a [relationship](/docs/{{version}}/eloquent-relationships) query: -#### Defining An Accessor + $flight->history()->withTrashed()->get(); -Eloquent provides a convenient way to transform your model attributes when getting or setting them. Simply define a `getFooAttribute` method on your model to declare an accessor. Keep in mind that the methods should follow camel-casing, even though your database columns are snake-case: +#### Retrieving Only Soft Deleted Models -class User extends Eloquent { +The `onlyTrashed` method will retrieve **only** soft deleted models: -public function getFirstNameAttribute($value) -{ -return ucfirst($value); -} + $flights = App\Flight::onlyTrashed() + ->where('airline_id', 1) + ->get(); -} +#### Restoring Soft Deleted Models -In the example above, the `first_name` column has an accessor. Note that the value of the attribute is passed to the accessor. +Sometimes you may wish to "un-delete" a soft deleted model. To restore a soft deleted model into an active state, use the `restore` method on a model instance: -#### Defining A Mutator + $flight->restore(); -Mutators are declared in a similar fashion: +You may also use the `restore` method in a query to quickly restore multiple models. Again, like other "mass" operations, this will not fire any model events for the models that are restored: -class User extends Eloquent { + App\Flight::withTrashed() + ->where('airline_id', 1) + ->restore(); -public function setFirstNameAttribute($value) -{ -$this->attributes['first_name'] = strtolower($value); -} +Like the `withTrashed` method, the `restore` method may also be used on [relationships](/docs/{{version}}/eloquent-relationships): -} + $flight->history()->restore(); - -## Date Mutators +#### Permanently Deleting Models -By default, Eloquent will convert the `created_at`, `updated_at`, and `deleted_at` columns to instances of [Carbon](https://github.com/briannesbitt/Carbon), which provides an assortment of helpful methods, and extends the native PHP `DateTime` class. +Sometimes you may need to truly remove a model from your database. To permanently remove a soft deleted model from the database, use the `forceDelete` method: -You may customize which fields are automatically mutated, and even completely disable this mutation, by overriding the `getDates` method of the model: + // Force deleting a single model instance... + $flight->forceDelete(); -public function getDates() -{ -return array('created_at'); -} + // Force deleting all related models... + $flight->history()->forceDelete(); -When a column is considered a date, you may set its value to a UNIX timestamp, date string (`Y-m-d`), date-time string, and of course a `DateTime` / `Carbon` instance. + +## Query Scopes -To totally disable date mutations, simply return an empty array from the `getDates` method: + +### Global Scopes -public function getDates() -{ -return array(); -} +Global scopes allow you to add constraints to all queries for a given model. Laravel's own [soft delete](#soft-deleting) functionality utilizes global scopes to only pull "non-deleted" models from the database. Writing your own global scopes can provide a convenient, easy way to make sure every query for a given model receives certain constraints. - -## Model Events +#### Writing Global Scopes -Eloquent models fire several events, allowing you to hook into various points in the model's lifecycle using the following methods: `creating`, `created`, `updating`, `updated`, `saving`, `saved`, `deleting`, `deleted`, `restoring`, `restored`. +Writing a global scope is simple. Define a class that implements the `Illuminate\Database\Eloquent\Scope` interface. This interface requires you to implement one method: `apply`. The `apply` method may add `where` constraints to the query as needed: -Whenever a new item is saved for the first time, the `creating` and `created` events will fire. If an item is not new and the `save` method is called, the `updating` / `updated` events will fire. In both cases, the `saving` / `saved` events will fire. + isValid()) return false; -}); + class AgeScope implements Scope + { + /** + * Apply the scope to a given Eloquent query builder. + * + * @param \Illuminate\Database\Eloquent\Builder $builder + * @param \Illuminate\Database\Eloquent\Model $model + * @return void + */ + public function apply(Builder $builder, Model $model) + { + $builder->where('age', '>', 200); + } + } -#### Setting A Model Boot Method +> {tip} There is not a predefined folder for scopes in a default Laravel application, so feel free to make your own `Scopes` folder within your Laravel application's `app` directory. -Eloquent models also contain a static `boot` method, which may provide a convenient place to register your event bindings. +#### Applying Global Scopes -class User extends Eloquent { +To assign a global scope to a model, you should override a given model's `boot` method and use the `addGlobalScope` method: -public static function boot() -{ -parent::boot(); + -## Model Observers + class User extends Model + { + /** + * The "booting" method of the model. + * + * @return void + */ + protected static function boot() + { + parent::boot(); -To consolidate the handling of model events, you may register a model observer. An observer class may have methods that correspond to the various model events. For example, `creating`, `updating`, `saving` methods may be on an observer, in addition to any other model event name. + static::addGlobalScope(new AgeScope); + } + } -So, for example, a model observer might look like this: +After adding the scope, a query to `User::all()` will produce the following SQL: -class UserObserver { + select * from `users` where `age` > 200 -public function saving($model) -{ -// -} +#### Anonymous Global Scopes -public function saved($model) -{ -// -} +Eloquent also allows you to define global scopes using Closures, which is particularly useful for simple scopes that do not warrant a separate class: -} + -## Arrays နှင့် JSON သို ့ပြောင်းလဲခြင်း + class User extends Model + { + /** + * The "booting" method of the model. + * + * @return void + */ + protected static function boot() + { + parent::boot(); -#### Model တစ်ခုကို Array သို ့ပြောင်းလဲခြင်း + static::addGlobalScope('age', function (Builder $builder) { + $builder->where('age', '>', 200); + }); + } + } -JSON APIs များ တည်ဆောက်ရာတွင် ၊ သင့် အနေဖြင့် model နှင့် ဆက်စပ်ပတ်သတ်သည်များကို array အနေဖြင့်သော လည်းကောင်း JSON အနေဖြင့်သော် လည်းကောင်း ထုတ်ပေးလိုသည့် အချိန်ကာလ များ ရှိပေမည်။ Eloquent အနေဖြင့် ထိုသို ့ပြုလုပ်နိုင်ရန် ထောက်ပံ့ပေးသော method များလည်း ရှိပေသည်။ ထိုသို ့ ၄င်းနှင့် တကွ ဆက်စပ်ပတ်သတ်နေသည်များကိုပါက array အဖြစ်ပြောင်းလဲ နိုင်ရန် `toArray` method ကို အသုံးပြုနိုင်သည်။ +#### Removing Global Scopes -$user = User::with('roles')->first(); +If you would like to remove a global scope for a given query, you may use the `withoutGlobalScope` method. The method accepts the class name of the global scope as its only argument: -return $user->toArray(); + User::withoutGlobalScope(AgeScope::class)->get(); -Models connection တစ်ခုလုံးပါ array အဖြစ် ပြောင်းလဲသွားသည်ကို သတိပြုရမည်။ +If you would like to remove several or even all of the global scopes, you may use the `withoutGlobalScopes` method: -return User::all()->toArray(); + // Remove all of the global scopes... + User::withoutGlobalScopes()->get(); -#### Model တစ်ခုကို JSON သို ့ ပြောင်းလဲခြင်း + // Remove some of the global scopes... + User::withoutGlobalScopes([ + FirstScope::class, SecondScope::class + ])->get(); -Model တစ်ခုကို JSON အနေဖြင့် ပြောင်းလဲလိုပါက `toJson` method ကို အသုံးပြုနိုင်သည်။ + +### Local Scopes -return User::find(1)->toJson(); +Local scopes allow you to define common sets of constraints that you may easily re-use throughout your application. For example, you may need to frequently retrieve all users that are considered "popular". To define a scope, simply prefix an Eloquent model method with `scope`. -#### Route တစ်ခုမှ Model ကို return ပြန်ခြင်း +Scopes should always return a query builder instance: -Model သို ့မဟုတ် collection တစ်ခုသည် string အဖြစ်သို ့ cast အလုပ်ခံရပါက အလိုအလျောက် JSON အဖြစ်သို ့ပြောင်းလဲသွားမည် ဖြစ်သည်။ -ထို ့ကြောင့် သင့် application route မှ တိုက်ရိုက် return ပြန်၍လည်း ရနိုင်သည်။ + where('votes', '>', 100); + } -class User extends Eloquent { + /** + * Scope a query to only include active users. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeActive($query) + { + return $query->where('active', 1); + } + } -protected $hidden = array('password'); +#### Utilizing A Local Scope -} +Once the scope has been defined, you may call the scope methods when querying the model. However, you do not need to include the `scope` prefix when calling the method. You can even chain calls to various scopes, for example: -> **Note:** When hiding relationships, use the relationship's **method** name, not the dynamic accessor name. + $users = App\User::popular()->active()->orderBy('created_at')->get(); -အပြန်အလှန်အားဖြင့် သင့်အနေဖြင့် ထုတ်ချင်သည်များကိုသာ ဖော်ပြနိုင်ရန် `visible` ဟုသည် property တစ်ခု ကြေညာနိုင်ပေသည်။ +#### Dynamic Scopes -protected $visible = array('first_name', 'last_name'); +Sometimes you may wish to define a scope that accepts parameters. To get started, just add your additional parameters to your scope. Scope parameters should be defined after the `$query` parameter: - -Occasionally, you may need to add array attributes that do not have a corresponding column in your database. To do so, simply define an accessor for the value: + attributes['admin'] == 'yes'; -} + namespace App; -Once you have created the accessor, just add the value to the `appends` property on the model: + use Illuminate\Database\Eloquent\Model; -protected $appends = array('is_admin'); + class User extends Model + { + /** + * Scope a query to only include users of a given type. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @param mixed $type + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeOfType($query, $type) + { + return $query->where('type', $type); + } + } + +Now, you may pass the parameters when calling the scope: + + $users = App\User::ofType('admin')->get(); + + +## Events + +Eloquent models fire several events, allowing you to hook into the following points in a model's lifecycle: `creating`, `created`, `updating`, `updated`, `saving`, `saved`, `deleting`, `deleted`, `restoring`, `restored`. Events allow you to easily execute code each time a specific model class is saved or updated in the database. + +Whenever a new model is saved for the first time, the `creating` and `created` events will fire. If a model already existed in the database and the `save` method is called, the `updating` / `updated` events will fire. However, in both cases, the `saving` / `saved` events will fire. + +To get started, define an `$events` property on your Eloquent model that maps various points of the Eloquent model's lifecycle to your own [event classes](/docs/{{version}}/events): + + UserSaved::class, + 'deleted' => UserDeleted::class, + ]; + } + + +### Observers + +If you are listening for many events on a given model, you may use observers to group all of your listeners into a single class. Observers classes have method names which reflect the Eloquent events you wish to listen for. Each of these methods receives the model as their only argument. Laravel does not include a default directory for observers, so you may create any directory you like to house your observer classes: + + +## Introduction + +Laravel's encrypter uses OpenSSL to provide AES-256 and AES-128 encryption. You are strongly encouraged to use Laravel's built-in encryption facilities and not attempt to roll your own "home grown" encryption algorithms. All of Laravel's encrypted values are signed using a message authentication code (MAC) so that their underlying value can not be modified once encrypted. + + +## Configuration + +Before using Laravel's encrypter, you must set a `key` option in your `config/app.php` configuration file. You should use the `php artisan key:generate` command to generate this key since this Artisan command will use PHP's secure random bytes generator to build your key. If this value is not properly set, all values encrypted by Laravel will be insecure. + + +## Using The Encrypter + +#### Encrypting A Value + +You may encrypt a value using the `encrypt` helper. All encrypted values are encrypted using OpenSSL and the `AES-256-CBC` cipher. Furthermore, all encrypted values are signed with a message authentication code (MAC) to detect any modifications to the encrypted string: + + fill([ + 'secret' => encrypt($request->secret) + ])->save(); + } + } + +#### Encrypting Without Serialization + +Encrypted values are passed through `serialize` during encryption, which allows for encryption of objects and arrays. Thus, non-PHP clients receiving encrypted values will need to `unserialize` the data. If you would like to encrypt and decrypt values without serialization, you may use the `encryptString` and `decryptString` methods of the `Crypt` facade: + + use Illuminate\Support\Facades\Crypt; + + $encrypted = Crypt::encryptString('Hello world.'); + + $decrypted = Crypt::decryptString($encrypted); + +#### Decrypting A Value + +You may decrypt values using the `decrypt` helper. If the value can not be properly decrypted, such as when the MAC is invalid, an `Illuminate\Contracts\Encryption\DecryptException` will be thrown: + + use Illuminate\Contracts\Encryption\DecryptException; + + try { + $decrypted = decrypt($encryptedValue); + } catch (DecryptException $e) { + // + } diff --git a/envoy.md b/envoy.md new file mode 100644 index 0000000..2155e6a --- /dev/null +++ b/envoy.md @@ -0,0 +1,180 @@ +# Envoy Task Runner + +- [Introduction](#introduction) + - [Installation](#installation) +- [Writing Tasks](#writing-tasks) + - [Setup](#setup) + - [Variables](#variables) + - [Stories](#stories) + - [Multiple Servers](#multiple-servers) +- [Running Tasks](#running-tasks) + - [Confirming Task Execution](#confirming-task-execution) +- [Notifications](#notifications) + - [Slack](#slack) + + +## Introduction + +[Laravel Envoy](https://github.com/laravel/envoy) provides a clean, minimal syntax for defining common tasks you run on your remote servers. Using Blade style syntax, you can easily setup tasks for deployment, Artisan commands, and more. Currently, Envoy only supports the Mac and Linux operating systems. + + +### Installation + +First, install Envoy using the Composer `global require` command: + + composer global require "laravel/envoy=~1.0" + +Since global Composer libraries can sometimes cause package version conflicts, you may wish to consider using `cgr`, which is a drop-in replacement for the `composer global require` command. The `cgr` library's installation instructions can be [found on GitHub](https://github.com/consolidation-org/cgr). + +> {note} Make sure to place the `~/.composer/vendor/bin` directory in your PATH so the `envoy` executable is found when running the `envoy` command in your terminal. + +#### Updating Envoy + +You may also use Composer to keep your Envoy installation up to date. Issuing the `composer global update` command will update all of your globally installed Composer packages: + + composer global update + + +## Writing Tasks + +All of your Envoy tasks should be defined in an `Envoy.blade.php` file in the root of your project. Here's an example to get you started: + + @servers(['web' => ['user@192.168.1.1']]) + + @task('foo', ['on' => 'web']) + ls -la + @endtask + +As you can see, an array of `@servers` is defined at the top of the file, allowing you to reference these servers in the `on` option of your task declarations. Within your `@task` declarations, you should place the Bash code that should run on your server when the task is executed. + +You can force a script to run locally by specifying the server's IP address as `127.0.0.1`: + + @servers(['localhost' => '127.0.0.1']) + + +### Setup + +Sometimes, you may need to execute some PHP code before executing your Envoy tasks. You may use the ```@setup``` directive to declare variables and do other general PHP work before any of your other tasks are executed: + + @setup + $now = new DateTime(); + + $environment = isset($env) ? $env : "testing"; + @endsetup + +If you need to require other PHP files before your task is executed, you may use the `@include` directive at the top of your `Envoy.blade.php` file: + + @include('vendor/autoload.php') + + @task('foo') + # ... + @endtask + + +### Variables + +If needed, you may pass option values into Envoy tasks using the command line: + + envoy run deploy --branch=master + +You may access the options in your tasks via Blade's "echo" syntax. Of course, you may also use `if` statements and loops within your tasks. For example, let's verify the presence of the `$branch` variable before executing the `git pull` command: + + @servers(['web' => '192.168.1.1']) + + @task('deploy', ['on' => 'web']) + cd site + + @if ($branch) + git pull origin {{ $branch }} + @endif + + php artisan migrate + @endtask + + +### Stories + +Stories group a set of tasks under a single, convenient name, allowing you to group small, focused tasks into large tasks. For instance, a `deploy` story may run the `git` and `composer` tasks by listing the task names within its definition: + + @servers(['web' => '192.168.1.1']) + + @story('deploy') + git + composer + @endstory + + @task('git') + git pull origin master + @endtask + + @task('composer') + composer install + @endtask + +Once the story has been written, you may run it just like a typical task: + + envoy run deploy + + +### Multiple Servers + +Envoy allows you to easily run a task across multiple servers. First, add additional servers to your `@servers` declaration. Each server should be assigned a unique name. Once you have defined your additional servers, list each of the servers in the task's `on` array: + + @servers(['web-1' => '192.168.1.1', 'web-2' => '192.168.1.2']) + + @task('deploy', ['on' => ['web-1', 'web-2']]) + cd site + git pull origin {{ $branch }} + php artisan migrate + @endtask + +#### Parallel Execution + +By default, tasks will be executed on each server serially. In other words, a task will finish running on the first server before proceeding to execute on the second server. If you would like to run a task across multiple servers in parallel, add the `parallel` option to your task declaration: + + @servers(['web-1' => '192.168.1.1', 'web-2' => '192.168.1.2']) + + @task('deploy', ['on' => ['web-1', 'web-2'], 'parallel' => true]) + cd site + git pull origin {{ $branch }} + php artisan migrate + @endtask + + +## Running Tasks + +To run a task or story that is defined in your `Envoy.blade.php` file, execute Envoy's `run` command, passing the name of the task or story you would like to execute. Envoy will run the task and display the output from the servers as the task is running: + + envoy run task + + +### Confirming Task Execution + +If you would like to be prompted for confirmation before running a given task on your servers, you should add the `confirm` directive to your task declaration. This option is particularly useful for destructive operations: + + @task('deploy', ['on' => 'web', 'confirm' => true]) + cd site + git pull origin {{ $branch }} + php artisan migrate + @endtask + + + +## Notifications + + +### Slack + +Envoy also supports sending notifications to [Slack](https://slack.com) after each task is executed. The `@slack` directive accepts a Slack hook URL and a channel name. You may retrieve your webhook URL by creating an "Incoming WebHooks" integration in your Slack control panel. You should pass the entire webhook URL into the `@slack` directive: + + @finished + @slack('webhook-url', '#bots') + @endfinished + +You may provide one of the following as the channel argument: + +
    +- To send the notification to a channel: `#channel` +- To send the notification to a user: `@user` +
    + diff --git a/errors.md b/errors.md index d713445..f4bdb32 100644 --- a/errors.md +++ b/errors.md @@ -1,117 +1,199 @@ # Errors & Logging +- [Introduction](#introduction) - [Configuration](#configuration) -- [Error တွေကို ထိန်းချုပ်ခြင်း](#handling-errors) + - [Error Detail](#error-detail) + - [Log Storage](#log-storage) + - [Log Severity Levels](#log-severity-levels) + - [Custom Monolog Configuration](#custom-monolog-configuration) +- [The Exception Handler](#the-exception-handler) + - [Report Method](#report-method) + - [Render Method](#render-method) - [HTTP Exceptions](#http-exceptions) -- [404 Errors များကို ထိန်းချုပ်ခြင်း](#handling-404-errors) + - [Custom HTTP Error Pages](#custom-http-error-pages) - [Logging](#logging) + +## Introduction + +When you start a new Laravel project, error and exception handling is already configured for you. The `App\Exceptions\Handler` class is where all exceptions triggered by your application are logged and then rendered back to the user. We'll dive deeper into this class throughout this documentation. + +For logging, Laravel utilizes the [Monolog](https://github.com/Seldaek/monolog) library, which provides support for a variety of powerful log handlers. Laravel configures several of these handlers for you, allowing you to choose between a single log file, rotating log files, or writing error information to the system log. + ## Configuration -Application ရဲ့ Logging Handler ကို `app/start/global.php` [start file](lifecycle#start-files) ထဲမှာ Registered လုပ်ထားပါတယ်။ နဂိုအတိုင်းကတော့ File တစ်ဖိုင်ထဲကိုပဲ အသုံးပြုခိုင်းထားပါတယ်။ သို့သော်လည်း သင့်စိတ်ကြိုက် ပြင်ဆင်နိုင်ပါတယ်။ Laravel က နာမည်ကြီး Loggin Library တစ်ခုဖြစ်တဲ့ [Monolog](https://github.com/Seldaek/monolog.md) ကိုသုံးထားတဲ့အတွက် Monolog မှာပါဝင်တဲ့ အမျိုးအမျိုးသော handler များကိုအသုံးပြုနိုင်ပါတယ်။ + +### Error Detail -ဥပမာ - Log File တစ်ခုတည်းမထားဘဲ နေ့စဉ်အလိုက် Log file တွေခွဲထားချင်တယ်ဆိုရင် ၊ start file မှာအောက်ကအတိုင်း ပြောင်းရေးလိုက်လို့ရပါတယ် +The `debug` option in your `config/app.php` configuration file determines how much information about an error is actually displayed to the user. By default, this option is set to respect the value of the `APP_DEBUG` environment variable, which is stored in your `.env` file. - $logFile = 'laravel.log'; +For local development, you should set the `APP_DEBUG` environment variable to `true`. In your production environment, this value should always be `false`. If the value is set to `true` in production, you risk exposing sensitive configuration values to your application's end users. - Log::useDailyFiles(storage_path().'/logs/'.$logFile); + +### Log Storage -### Error အသေးစိတ် +Out of the box, Laravel supports writing log information to `single` files, `daily` files, the `syslog`, and the `errorlog`. To configure which storage mechanism Laravel uses, you should modify the `log` option in your `config/app.php` configuration file. For example, if you wish to use daily log files instead of a single file, you should set the `log` value in your `app` configuration file to `daily`: -အရင်အတိုင်းဆို ၊ Error ရဲ့အသေးစိတ်ကို ဖော်ပြပါလိမ့်မယ်။ ဆိုလိုတာက Application မှာ Error တစ်ခုတက်နေမယ်ဆိုရင် ၊ အဲဒီ Error ရဲ့အသေးစိတ်နဲ့ ၊ အဲဒီ Error နဲ့ပတ်သက်နေတဲ့ ဖိုင်တွေနဲ့ အသေးစိတ်အချက်အလက်တွေကို ဖော်ပြပေးပါလိမ့်မယ်။ ဒီ Error အသေးစိတ်ပြတဲ့ Feature ကို ပိတ်ချင်တယ်ဆိုရင်တော့ `app/config/app.php` ထဲမှာ `debug` option ကို `false` လို့ လုပ်ပေးလိုက်ရုံပါပဲ။ + 'log' => 'daily' -> **မှတ်ချက်:** Application တကယ် Run ပြီဆိုရင်တော့ ဒီ Feature ကို ပိတ်ထားဖို့အတွက် အကြံပြုချင်ပါတယ်။ +#### Maximum Daily Log Files - -## Error တွေကို ထိန်းချုပ်ခြင်း +When using the `daily` log mode, Laravel will only retain five days of log files by default. If you want to adjust the number of retained files, you may add a `log_max_files` configuration value to your `app` configuration file: -Default အနေနဲ့က `app/start/global.php` ထဲမှာ Exception တွေတိုင်းအတွက် Error Handler တစ်ခုပါရှိပါတယ်။ + 'log_max_files' => 30 - App::error(function(Exception $exception) - { - Log::error($exception); - }); + +### Log Severity Levels -ဒါကတော့ အရမ်းရိုးရှင်းတဲ့ Error Handler တစ်ခုပဲဖြစ်ပါတယ်။ တကယ်လို့ လိုအပ်မယ်ဆိုရင်တော့ ရှုပ်ထွေးတဲ့ Handler တွေကို သတ်မှတ်ပေးနိုင်ပါတယ်။ Exception တွေရဲ့နာမည်ပေါ်မူတည်ပြီး Handler တွေကိုခေါ်ပါတယ်။ ဥပမာပေးရမယ်ဆိုရင် ၊ `RunetimeException` အတွက်ပဲ handle လုပ်တဲ့ handler ကို အောက်ကအတိုင်း ရေးရပါမယ်။ +When using Monolog, log messages may have different levels of severity. By default, Laravel writes all log levels to storage. However, in your production environment, you may wish to configure the minimum severity that should be logged by adding the `log_level` option to your `app.php` configuration file. - App::error(function(RuntimeException $exception) - { - // Handle the exception... - }); +Once this option has been configured, Laravel will log all levels greater than or equal to the specified severity. For example, a default `log_level` of `error` will log **error**, **critical**, **alert**, and **emergency** messages: -Exception Handler တစ်ခုက Response တစ်ခု Return ပြန်မယ်ဆိုရင် အဲဒီ Response ကိုပဲ Browser မှာဖော်ပြမှာဖြစ်ပြီး ၊ တစ်ခြားသော Error Handler တွေကိုခေါ်မှာမဟုတ်ပါဘူး + 'log_level' => env('APP_LOG_LEVEL', 'error'), - App::error(function(InvalidUserException $exception) - { - Log::error($exception); +> {tip} Monolog recognizes the following severity levels - from least severe to most severe: `debug`, `info`, `notice`, `warning`, `error`, `critical`, `alert`, `emergency`. - return 'Sorry! Something is wrong with this account!'; - }); + +### Custom Monolog Configuration -PHP fatal error ဖြစ်တဲ့အချိန်ကို စောင့်ဖမ်းချင်ရင်တော့ `App::fatal` method ကိုသုံးရပါမယ် +If you would like to have complete control over how Monolog is configured for your application, you may use the application's `configureMonologUsing` method. You should place a call to this method in your `bootstrap/app.php` file right before the `$app` variable is returned by the file: - App::fatal(function($exception) - { - // - }); + $app->configureMonologUsing(function ($monolog) { + $monolog->pushHandler(...); + }); -Handler တွေအများကြီးရှိတယ်ဆိုရင်တော့ General ကြတဲ့ Handler တွေမှ အသေးစိတ်ကျတဲ့ handler တွေအထိအစဉ်လိုက် သတ်မှတ်ပေးသင့်ပါတယ်။ ဥပမာ - `Exception` တွေအားလုံးကို handler လုပ်တဲ့ handler တွေကိုအရင်ဆုံး သတ်မှတ်ပါ၊ ပြီးမှ `Illuminate\Encryption\DecryptException` လိုမျိုး အသေးစိတ် exception ကိုတော့ နောက်မှသတ်မှတ်ပေးပါ။ + return $app; -### Error Handlers တွေကို ဘယ်မှာရေးရမလဲ + +## The Exception Handler -Error Handler တွေကို သတ်မှတ်ပေးရမယ့် နေရာဆိုပြီးမသတ်မှတ်ထားပါဘူး။ ဒါနဲ့ပတ်သက်ပြီးလို့ကတော့ Laravel က လွတ်လပ်ခွင့်ပေးထားပါတယ်။ နည်းလမ်းတစ်ခုကတော့ `start/global.php` ထဲမှာ ထည့်ရေးနိုင်ပါတယ်။ အဲဒီနေရာက Application စစ Run ချင်း Code တွေထည့်ရေးသင့်တဲ့ အကောင်းဆုံးနေရာပါဘဲ။ အဲဒီဖိုင်ထဲမှာ တစ်ခြားရေးထားတာတွေ များနေတယ်ဆိုရင်တော့ `app/errors.php` ဆိုပြီး ဖိုင်ဆောက်လိုက်ပြီးတော့ `start/global.php` ထဲမှာ `require` လုပ်ပြီးရေးလို့ရပါတယ်။ တတိယနည်းလမ်းကတော့ Handler တွေအားလုံးကို ထိန်းချုပ်ပေးမယ့် [service provider](ioc#service-providers.md) တစ်ခု ဖန်းတီးလိုက်ပါ။ နောက်ထပ်တစ်ခေါက်ထပ်ပြောချင်ပါတယ် ၊ အဖြေမှန်ဆိုပြီးရယ်လို့ မရှိပါဘူး။ သင်နဲ့အကိုက်ညီဆုံးပုံစံအသုံးပြုပါ။ + +### The Report Method - -## HTTP Exceptions +All exceptions are handled by the `App\Exceptions\Handler` class. This class contains two methods: `report` and `render`. We'll examine each of these methods in detail. The `report` method is used to log exceptions or send them to an external service like [Bugsnag](https://bugsnag.com) or [Sentry](https://github.com/getsentry/sentry-laravel). By default, the `report` method simply passes the exception to the base class where the exception is logged. However, you are free to log exceptions however you wish. -အချို့ Exception တွေက Server ကနေပြီးတော့ HTTP error code တွေဖော်ပြပေးပါတယ်။ ဥပမာ - "page not found" error (404), "unauthorized error" (401) သို့မဟုတ် 500 error လိုမျိုးဖြစ်ပါတယ်။ ဒီလို Response အတွက်တွေဆို အောက်ကအတိုင်းသုံးပါ။ +For example, if you need to report different types of exceptions in different ways, you may use the PHP `instanceof` comparison operator: - App::abort(404); + /** + * Report or log an exception. + * + * This is a great spot to send exceptions to Sentry, Bugsnag, etc. + * + * @param \Exception $exception + * @return void + */ + public function report(Exception $exception) + { + if ($exception instanceof CustomException) { + // + } -ကိုယ်ပိုင် message နဲ့ response လုပ်ပေးချင်လဲရပါတယ်။ + return parent::report($exception); + } - App::abort(403, 'Unauthorized action.'); +#### Ignoring Exceptions By Type -အဲဒီ method ကို Application တစ်ခုလုံးရဲ့ request တွေအားလုံးမှာ အသုံးပြုမှာပါ။ +The `$dontReport` property of the exception handler contains an array of exception types that will not be logged. For example, exceptions resulting from 404 errors, as well as several other types of errors, are not written to your log files. You may add other exception types to this array as needed: - -## 404 Errors များကို ထိန်းချုပ်ခြင်း + /** + * A list of the exception types that should not be reported. + * + * @var array + */ + protected $dontReport = [ + \Illuminate\Auth\AuthenticationException::class, + \Illuminate\Auth\Access\AuthorizationException::class, + \Symfony\Component\HttpKernel\Exception\HttpException::class, + \Illuminate\Database\Eloquent\ModelNotFoundException::class, + \Illuminate\Validation\ValidationException::class, + ]; -"404 Not Found" error တွေအားလုံးကို ထိန်းချုပ်ပေးမယ့် handler ကိုလဲ ကိုယ့်စိတ်ကြိုက်ပုံစံနဲ့ အလွယ်တကူသတ်မှတ်ပေးနိုင်ပါတယ်။ + +### The Render Method - App::missing(function($exception) - { - return Response::view('errors.missing', array(), 404); - }); +The `render` method is responsible for converting a given exception into an HTTP response that should be sent back to the browser. By default, the exception is passed to the base class which generates a response for you. However, you are free to check the exception type or return your own custom response: + + /** + * Render an exception into an HTTP response. + * + * @param \Illuminate\Http\Request $request + * @param \Exception $exception + * @return \Illuminate\Http\Response + */ + public function render($request, Exception $exception) + { + if ($exception instanceof CustomException) { + return response()->view('errors.custom', [], 500); + } + + return parent::render($request, $exception); + } + + +## HTTP Exceptions + +Some exceptions describe HTTP error codes from the server. For example, this may be a "page not found" error (404), an "unauthorized error" (401) or even a developer generated 500 error. In order to generate such a response from anywhere in your application, you may use the `abort` helper: + + abort(404); + +The `abort` helper will immediately raise an exception which will be rendered by the exception handler. Optionally, you may provide the response text: + + abort(403, 'Unauthorized action.'); + + +### Custom HTTP Error Pages + +Laravel makes it easy to display custom error pages for various HTTP status codes. For example, if you wish to customize the error page for 404 HTTP status codes, create a `resources/views/errors/404.blade.php`. This file will be served on all 404 errors generated by your application. The views within this directory should be named to match the HTTP status code they correspond to. The `HttpException` instance raised by the `abort` function will be passed to the view as an `$exception` variable. ## Logging -အရမ်းလန်းတဲ့ [Monolog](http://github.com/seldaek/monolog) library ကို သုံးရပိုလွယ်အောင်လို့ Laravel logging အထောက်အပံ့တွေက ကူညီပေးပါတယ်။ Default အနေနဲ့ Log File တစ်ခုတည်းကိုပဲ သုံးအောင်လို့ သတ်မှတ်ပေးထားပါတယ်။ အဲဒီဖိုင်က `app/storage/logs/laravel.log` ဖြစ်ပါတယ်။ Log file ထဲကို အောက်ကအတိုင်း Log တွေရိုက်ထည့်နိုင်ပါတယ် +Laravel provides a simple abstraction layer on top of the powerful [Monolog](https://github.com/seldaek/monolog) library. By default, Laravel is configured to create a log file for your application in the `storage/logs` directory. You may write information to the logs using the `Log` [facade](/docs/{{version}}/facades): + + User::findOrFail($id)]); + } + } +The logger provides the eight logging levels defined in [RFC 5424](https://tools.ietf.org/html/rfc5424): **emergency**, **alert**, **critical**, **error**, **warning**, **notice**, **info** and **debug**. -Array ပုံစံနဲ့လည်း ထည့်ပေးလိုက်လို့ရပါတယ် + Log::emergency($message); + Log::alert($message); + Log::critical($message); + Log::error($message); + Log::warning($message); + Log::notice($message); + Log::info($message); + Log::debug($message); - Log::info('Log message', array('context' => 'Other helpful information')); +#### Contextual Information -Monolog မှာ တစ်ခြား handler တွေ အများကြီးပါဝင်ပါတယ်။ လိုအပ်ရင် Laravel သုံးထားတဲံ Monolog instance ကိုသုံးနိုင်ပါတယ်။ +An array of contextual data may also be passed to the log methods. This contextual data will be formatted and displayed with the log message: - $monolog = Log::getMonolog(); + Log::info('User failed to login.', ['id' => $user->id]); -Log ဖိုင်ထဲကို ထည့်သမျှ message တွေအားလုံးကို စောင့်ဖမ်းဖို့အတွက်လဲ event ရေးထားလို့ရပါတယ်။ +#### Accessing The Underlying Monolog Instance -#### Registering A Log Listener +Monolog has a variety of additional handlers you may use for logging. If needed, you may access the underlying Monolog instance being used by Laravel: - Log::listen(function($level, $message, $context) - { - // - }); + $monolog = Log::getMonolog(); diff --git a/events.md b/events.md index 21ed090..acb5322 100644 --- a/events.md +++ b/events.md @@ -1,175 +1,356 @@ # Events -- [Basic Usage](#basic-usage) -- [Wildcard Listeners](#wildcard-listeners) -- [Using Classes As Listeners](#using-classes-as-listeners) -- [Queued Events](#queued-events) +- [Introduction](#introduction) +- [Registering Events & Listeners](#registering-events-and-listeners) + - [Generating Events & Listeners](#generating-events-and-listeners) + - [Manually Registering Events](#manually-registering-events) +- [Defining Events](#defining-events) +- [Defining Listeners](#defining-listeners) +- [Queued Event Listeners](#queued-event-listeners) + - [Manually Accessing The Queue](#manually-accessing-the-queue) + - [Handling Failed Jobs](#handling-failed-jobs) +- [Dispatching Events](#dispatching-events) - [Event Subscribers](#event-subscribers) + - [Writing Event Subscribers](#writing-event-subscribers) + - [Registering Event Subscribers](#registering-event-subscribers) - -## Basic Usage + +## Introduction -The Laravel `Event` class provides a simple observer implementation, allowing you to subscribe and listen for events in your application. +Laravel's events provides a simple observer implementation, allowing you to subscribe and listen for various events that occur in your application. Event classes are typically stored in the `app/Events` directory, while their listeners are stored in `app/Listeners`. Don't worry if you don't see these directories in your application, since they will be created for you as you generate events and listeners using Artisan console commands. -#### Subscribing To An Event +Events serve as a great way to decouple various aspects of your application, since a single event can have multiple listeners that do not depend on each other. For example, you may wish to send a Slack notification to your user each time an order has shipped. Instead of coupling your order processing code to your Slack notification code, you can simply raise an `OrderShipped` event, which a listener can receive and transform into a Slack notification. - Event::listen('auth.login', function($user) - { - $user->last_login = new DateTime; + +## Registering Events & Listeners - $user->save(); - }); +The `EventServiceProvider` included with your Laravel application provides a convenient place to register all of your application's event listeners. The `listen` property contains an array of all events (keys) and their listeners (values). Of course, you may add as many events to this array as your application requires. For example, let's add a `OrderShipped` event: -#### Firing An Event + /** + * The event listener mappings for the application. + * + * @var array + */ + protected $listen = [ + 'App\Events\OrderShipped' => [ + 'App\Listeners\SendShipmentNotification', + ], + ]; - $event = Event::fire('auth.login', array($user)); + +### Generating Events & Listeners -#### Subscribing To Events With Priority +Of course, manually creating the files for each event and listener is cumbersome. Instead, simply add listeners and events to your `EventServiceProvider` and use the `event:generate` command. This command will generate any events or listeners that are listed in your `EventServiceProvider`. Of course, events and listeners that already exist will be left untouched: -You may also specify a priority when subscribing to events. Listeners with higher priority will be run first, while listeners that have the same priority will be run in order of subscription. + php artisan event:generate - Event::listen('auth.login', 'LoginHandler', 10); + +### Manually Registering Events - Event::listen('auth.login', 'OtherHandler', 5); +Typically, events should be registered via the `EventServiceProvider` `$listen` array; however, you may also register Closure based events manually in the `boot` method of your `EventServiceProvider`: -#### Stopping The Propagation Of An Event + /** + * Register any other events for your application. + * + * @return void + */ + public function boot() + { + parent::boot(); -Sometimes, you may wish to stop the propagation of an event to other listeners. You may do so using by returning `false` from your listener: + Event::listen('event.name', function ($foo, $bar) { + // + }); + } - Event::listen('auth.login', function($event) - { - // Handle the event... +#### Wildcard Event Listeners - return false; - }); +You may even register listeners using the `*` as a wildcard parameter, allowing you to catch multiple events on the same listener. Wildcard listeners receive the event name as their first argument, and the entire event data array as their second argument: -### Where To Register Events + Event::listen('event.*', function ($eventName, array $data) { + // + }); -So, you know how to register events, but you may be wondering _where_ to register them. Don't worry, this is a common question. Unfortunately, it's a hard question to answer because you can register an event almost anywhere! But, here are some tips. Again, like most other bootstrapping code, you may register events in one of your `start` files such as `app/start/global.php`. + +## Defining Events -If your `start` files are getting too crowded, you could create a separate `app/events.php` file that is included from a `start` file. This is a simple solution that keeps your event registration cleanly separated from the rest of your bootstrapping. If you prefer a class based approach, you may register your events in a [service provider](ioc#service-providers.md). Since none of these approaches is inherently "correct", choose an approach you feel comfortable with based on the size of your application. +An event class is simply a data container which holds the information related to the event. For example, let's assume our generated `OrderShipped` event receives an [Eloquent ORM](/docs/{{version}}/eloquent) object: - -## Wildcard Listeners + order = $order; + } + } - Event::listen('foo.*', function($param) - { - if (Event::firing() == 'foo.bar') - { - // - } - }); +As you can see, this event class contains no logic. It is simply a container for the `Order` instance that was purchased. The `SerializesModels` trait used by the event will gracefully serialize any Eloquent models if the event object is serialized using PHP's `serialize` function. - -## Using Classes As Listeners + +## Defining Listeners -In some cases, you may wish to use a class to handle an event rather than a Closure. Class event listeners will be resolved out of the [Laravel IoC container](ioc.md), providing you the full power of dependency injection on your listeners. +Next, let's take a look at the listener for our example event. Event listeners receive the event instance in their `handle` method. The `event:generate` command will automatically import the proper event class and type-hint the event on the `handle` method. Within the `handle` method, you may perform any actions necessary to respond to the event: -#### Registering A Class Listener + order... + } + } - public function handle($data) - { - // - } +> {tip} Your event listeners may also type-hint any dependencies they need on their constructors. All event listeners are resolved via the Laravel [service container](/docs/{{version}}/container), so dependencies will be injected automatically. - } +#### Stopping The Propagation Of An Event -#### Specifying Which Method To Subscribe +Sometimes, you may wish to stop the propagation of an event to other listeners. You may do so by returning `false` from your listener's `handle` method. -If you do not wish to use the default `handle` method, you may specify the method that should be subscribed: + +## Queued Event Listeners - Event::listen('auth.login', 'LoginHandler@onLogin'); +Queueing listeners can be beneficial if your listener is going to perform a slow task such as sending an e-mail or making an HTTP request. Before getting started with queued listeners, make sure to [configure your queue](/docs/{{version}}/queues) and start a queue listener on your server or local development environment. - -## Queued Events +To specify that a listener should be queued, add the `ShouldQueue` interface to the listener class. Listeners generated by the `event:generate` Artisan command already have this interface imported into the current namespace, so you can use it immediately: -#### Registering A Queued Event + -## Event Subscribers + +### Manually Accessing The Queue + +If you need to manually access the listener's underlying queue job's `delete` and `release` methods, you may do so using the `Illuminate\Queue\InteractsWithQueue` trait. This trait is imported by default on generated listeners and provides access to these methods: + + release(30); + } + } + } - /** - * Handle user logout events. - */ - public function onUserLogout($event) - { - // - } + +### Handling Failed Jobs - /** - * Register the listeners for the subscriber. - * - * @param Illuminate\Events\Dispatcher $events - * @return array - */ - public function subscribe($events) - { - $events->listen('auth.login', 'UserEventHandler@onUserLogin'); +Sometimes your queued event listeners may fail. If queued listener exceeds the maximum number of attempts as defined by your queue worker, the `failed` method will be called on your listener. The `failed` method receives the event instance and the exception that caused the failure: - $events->listen('auth.logout', 'UserEventHandler@onUserLogout'); - } + +## Dispatching Events - Event::subscribe('UserEventHandler'); +To dispatch an event, you may pass an instance of the event to the `event` helper. The helper will dispatch the event to all of its registered listeners. Since the `event` helper is globally available, you may call it from anywhere in your application: + + {tip} When testing, it can be helpful to assert that certain events were dispatched without actually triggering their listeners. Laravel's [built-in testing helpers](/docs/{{version}}/mocking#mocking-events) makes it a cinch. + + +## Event Subscribers + +### Writing Event Subscribers + +Event subscribers are classes that may subscribe to multiple events from within the class itself, allowing you to define several event handlers within a single class. Subscribers should define a `subscribe` method, which will be passed an event dispatcher instance. You may call the `listen` method on the given dispatcher to register event listeners: + + listen( + 'Illuminate\Auth\Events\Login', + 'App\Listeners\UserEventSubscriber@onUserLogin' + ); + + $events->listen( + 'Illuminate\Auth\Events\Logout', + 'App\Listeners\UserEventSubscriber@onUserLogout' + ); + } + + } + + +### Registering Event Subscribers + +After writing the subscriber, you are ready to register it with the event dispatcher. You may register subscribers using the `$subscribe` property on the `EventServiceProvider`. For example, let's add the `UserEventSubscriber` to the list: + + -## Introduction - -Laravel offers many extension points for you to customize the behavior of the framework's core components, or even replace them entirely. For example, the hashing facilities are defined by a `HasherInterface` contract, which you may implement based on your application's requirements. You may also extend the `Request` object, allowing you to add your own convenient "helper" methods. You may even add entirely new authentication, cache, and session drivers! - -Laravel components are generally extended in two ways: binding new implementations in the IoC container, or registering an extension with a `Manager` class, which are implementations of the "Factory" design pattern. In this chapter we'll explore the various methods of extending the framework and examine the necessary code. - -> **Note:** Remember, Laravel components are typically extended in one of two ways: IoC bindings and the `Manager` classes. The manager classes serve as an implementation of the "factory" design pattern, and are responsible for instantiating driver based facilities such as cache and session. - - -## Managers & Factories - -Laravel has several `Manager` classes that manage the creation of driver-based components. These include the cache, session, authentication, and queue components. The manager class is responsible for creating a particular driver implementation based on the application's configuration. For example, the `CacheManager` class can create APC, Memcached, File, and various other implementations of cache drivers. - -Each of these managers includes an `extend` method which may be used to easily inject new driver resolution functionality into the manager. We'll cover each of these managers below, with examples of how to inject custom driver support into each of them. - -> **Note:** Take a moment to explore the various `Manager` classes that ship with Laravel, such as the `CacheManager` and `SessionManager`. Reading through these classes will give you a more thorough understanding of how Laravel works under the hood. All manager classes extend the `Illuminate\Support\Manager` base class, which provides some helpful, common functionality for each manager. - - -## Where To Extend - -This documentation covers how to extend a variety of Laravel's components, but you may be wondering where to place your extension code. Like most other bootstrapping code, you are free to place some extensions in your `start` files. Cache and Auth extensions are good candidates for this approach. Other extensions, like `Session`, must be placed in the `register` method of a service provider since they are needed very early in the request life-cycle. - - -## Cache - -To extend the Laravel cache facility, we will use the `extend` method on the `CacheManager`, which is used to bind a custom driver resolver to the manager, and is common across all manager classes. For example, to register a new cache driver named "mongo", we would do the following: - - Cache::extend('mongo', function($app) - { - // Return Illuminate\Cache\Repository instance... - }); - -The first argument passed to the `extend` method is the name of the driver. This will correspond to your `driver` option in the `app/config/cache.php` configuration file. The second argument is a Closure that should return an `Illuminate\Cache\Repository` instance. The Closure will be passed an `$app` instance, which is an instance of `Illuminate\Foundation\Application` and an IoC container. - -To create our custom cache driver, we first need to implement the `Illuminate\Cache\StoreInterface` contract. So, our MongoDB cache implementation would look something like this: - - class MongoStore implements Illuminate\Cache\StoreInterface { - - public function get($key) {} - public function put($key, $value, $minutes) {} - public function increment($key, $value = 1) {} - public function decrement($key, $value = 1) {} - public function forever($key, $value) {} - public function forget($key) {} - public function flush() {} - - } - -We just need to implement each of these methods using a MongoDB connection. Once our implementation is complete, we can finish our custom driver registration: - - use Illuminate\Cache\Repository; - - Cache::extend('mongo', function($app) - { - return new Repository(new MongoStore); - }); - -As you can see in the example above, you may use the base `Illuminate\Cache\Repository` when creating custom cache drivers. There is typically no need to create your own repository class. - -If you're wondering where to put your custom cache driver code, consider making it available on Packagist! Or, you could create an `Extensions` namespace within your application's primary folder. For example, if the application is named `Snappy`, you could place the cache extension in `app/Snappy/Extensions/MongoStore.php`. However, keep in mind that Laravel does not have a rigid application structure and you are free to organize your application according to your preferences. - -> **Note:** If you're ever wondering where to put a piece of code, always consider a service provider. As we've discussed, using a service provider to organize framework extensions is a great way to organize your code. - - -## Session - -Extending Laravel with a custom session driver is just as easy as extending the cache system. Again, we will use the `extend` method to register our custom code: - - Session::extend('mongo', function($app) - { - // Return implementation of SessionHandlerInterface - }); - -### Where To Extend The Session - -Session extensions need to be registered differently than other extensions like Cache and Auth. Since sessions are started very early in the request-lifecycle, registering the extensions in a `start` file will happen be too late. Instead, a [service provider](ioc#service-providers.md) will be needed. You should place your session extension code in the `register` method of your service provider, and the provider should be placed **below** the default `Illuminate\Session\SessionServiceProvider` in the `providers` configuration array. - -### Writing The Session Extension - -Note that our custom cache driver should implement the `SessionHandlerInterface`. This interface is included in the PHP 5.4+ core. If you are using PHP 5.3, the interface will be defined for you by Laravel so you have forward-compatibility. This interface contains just a few simple methods we need to implement. A stubbed MongoDB implementation would look something like this: - - class MongoHandler implements SessionHandlerInterface { - - public function open($savePath, $sessionName) {} - public function close() {} - public function read($sessionId) {} - public function write($sessionId, $data) {} - public function destroy($sessionId) {} - public function gc($lifetime) {} - - } - -Since these methods are not as readily understandable as the cache `StoreInterface`, let's quickly cover what each of the methods do: - -- The `open` method would typically be used in file based session store systems. Since Laravel ships with a `file` session driver, you will almost never need to put anything in this method. You can leave it as an empty stub. It is simply a fact of poor interface design (which we'll discuss later) that PHP requires us to implement this method. -- The `close` method, like the `open` method, can also usually be disregarded. For most drivers, it is not needed. -- The `read` method should return the string version of the session data associated with the given `$sessionId`. There is no need to do any serialization or other encoding when retrieving or storing session data in your driver, as Laravel will perform the serialization for you. -- The `write` method should write the given `$data` string associated with the `$sessionId` to some persistent storage system, such as MongoDB, Dynamo, etc. -- The `destroy` method should remove the data associated with the `$sessionId` from persistent storage. -- The `gc` method should destroy all session data that is older than the given `$lifetime`, which is a UNIX timestamp. For self-expiring systems like Memcached and Redis, this method may be left empty. - -Once the `SessionHandlerInterface` has been implemented, we are ready to register it with the Session manager: - - Session::extend('mongo', function($app) - { - return new MongoHandler; - }); - -Once the session driver has been registered, we may use the `mongo` driver in our `app/config/session.php` configuration file. - -> **Note:** Remember, if you write a custom session handler, share it on Packagist! - - -## Authentication - -Authentication may be extended the same way as the cache and session facilities. Again, we will use the `extend` method we have become familiar with: - - Auth::extend('riak', function($app) - { - // Return implementation of Illuminate\Auth\UserProviderInterface - }); - -The `UserProviderInterface` implementations are only responsible for fetching a `UserInterface` implementation out of a persistent storage system, such as MySQL, Riak, etc. These two interfaces allow the Laravel authentication mechanisms to continue functioning regardless of how the user data is stored or what type of class is used to represent it. - -Let's take a look at the `UserProviderInterface`: - - interface UserProviderInterface { - - public function retrieveById($identifier); - public function retrieveByCredentials(array $credentials); - public function validateCredentials(UserInterface $user, array $credentials); - - } - -The `retrieveById` function typically receives a numeric key representing the user, such as an auto-incrementing ID from a MySQL database. The `UserInterface` implementation matching the ID should be retrieved and returned by the method. - -The `retrieveByCredentials` method receives the array of credentials passed to the `Auth::attempt` method when attempting to sign into an application. The method should then "query" the underlying persistent storage for the user matching those credentials. Typically, this method will run a query with a "where" condition on `$credentials['username']`. **This method should not attempt to do any password validation or authentication.** - -The `validateCredentials` method should compare the given `$user` with the `$credentials` to authenticate the user. For example, this method might compare the `$user->getAuthPassword()` string to a `Hash::make` of `$credentials['password']`. - -Now that we have explored each of the methods on the `UserProviderInterface`, let's take a look at the `UserInterface`. Remember, the provider should return implementations of this interface from the `retrieveById` and `retrieveByCredentials` methods: - - interface UserInterface { - - public function getAuthIdentifier(); - public function getAuthPassword(); - - } - -This interface is simple. The `getAuthIdentifier` method should return the "primary key" of the user. In a MySQL back-end, again, this would be the auto-incrementing primary key. The `getAuthPassword` should return the user's hashed password. This interface allows the authentication system to work with any User class, regardless of what ORM or storage abstraction layer you are using. By default, Laravel includes a `User` class in the `app/models` directory which implements this interface, so you may consult this class for an implementation example. - -Finally, once we have implemented the `UserProviderInterface`, we are ready to register our extension with the `Auth` facade: - - Auth::extend('riak', function($app) - { - return new RiakUserProvider($app['riak.connection']); - }); - -After you have registered the driver with the `extend` method, you switch to the new driver in your `app/config/auth.php` configuration file. - - -## IoC Based Extension - -Almost every service provider included with the Laravel framework binds objects into the IoC container. You can find a list of your application's service providers in the `app/config/app.php` configuration file. As you have time, you should skim through each of these provider's source code. By doing so, you will gain a much better understanding of what each provider adds to the framework, as well as what keys are used to bind various services into the IoC container. - -For example, the `HashServiceProvider` binds a `hash` key into the IoC container, which resolves into a `Illuminate\Hashing\BcryptHasher` instance. You can easily extend and override this class within your own application by overriding this IoC binding. For example: - - class SnappyHashProvider extends Illuminate\Hashing\HashServiceProvider { - - public function boot() - { - App::bindShared('hash', function() - { - return new Snappy\Hashing\ScryptHasher; - }); - - parent::boot(); - } - - } - -Note that this class extends the `HashServiceProvider`, not the default `ServiceProvider` base class. Once you have extended the service provider, swap out the `HashServiceProvider` in your `app/config/app.php` configuration file with the name of your extended provider. - -This is the general method of extending any core class that is bound in the container. Essentially every core class is bound in the container in this fashion, and can be overridden. Again, reading through the included framework service providers will familiarize you with where various classes are bound into the container, and what keys they are bound by. This is a great way to learn more about how Laravel is put together. - - -## Request Extension - -Because it is such a foundational piece of the framework and is instantiated very early in the request cycle, extending the `Request` class works a little differently than the previous examples. - -First, extend the class like normal: - - -## မိတ်ဆက် +## Introduction -Facades (ဖဆော့စ် ဟုအသံထွက်ပါ) က Application ရဲ့ [IoC container](ioc.md) ထဲမှာရှိတဲ့ Class တွေကို static ပုံစံမျိုးသုံးနိုင်အောင် လုပ်ပေးပါတယ်။ Laravel မှာလဲ Facades တွေအများကြီးပါဝင်ပြီးတော့ အဲဒီ Facade တွေကိုလည်း သုံးဖူးပါလိမ့်မယ်။ သင်သုံးဖူးပေမယ့်လည်း သုံးဖူးမှန်းမသိဖြစ်နေတက်ပါတယ်။ Laravel "facades" တွေက Static Proxy တွေအနေနဲ့ ကူညီပေးပါတယ်။ ၄င်းက သာမာန် Static method တွေမဟုတ်ဘဲ ၊ ဖတ်/မှတ်လို့ကောင်းပြီး ပိုပြီးတိုတောင်းတဲ့ Syntax ပုံစံတွေဖြစ်စေတဲ့အပြင် Test လုပ်လို့အဆင်ပြေပြီး ပြောင်းလွယ်ပြင်လွယ်ဖြစ်စေပါတယ်။ +Facades provide a "static" interface to classes that are available in the application's [service container](/docs/{{version}}/container). Laravel ships with many facades which provide access to almost all of Laravel's features. Laravel facades serve as "static proxies" to underlying classes in the service container, providing the benefit of a terse, expressive syntax while maintaining more testability and flexibility than traditional static methods. -အခါအားလျောက်စွာ သင့် Application နဲ့ Package တွေ အတွက် သင့်ကိုယ်ပိုင် Facades တွေတည်ဆောက်နိုင်ပါတယ်။ ဒါ့ကြောင့် ဒီ Class တွေရဲ့ အသုံးပြုပုံတွေ နဲ့ အယူအစတွေကို မွှေနှောက်ကြည့်ကြရအောင်။ +All of Laravel's facades are defined in the `Illuminate\Support\Facades` namespace. So, we can easily access a facade like so: -> **မှတ်ချက်:** Facades ကိုမလေ့လာခင် ၊ Laravel ရဲ့ [IoC container](ioc.md) နဲ့သေချာရင်းနှီးနေဖို့ အကြံပြုချင်ပါတယ်။ + use Illuminate\Support\Facades\Cache; - -## ရှင်းလင်းချက် + Route::get('/cache', function () { + return Cache::get('key'); + }); -Facade ဆိုတာ Class တစ်ခုဖြစ်ပြီး Container ထဲက Object ကို ခေါ်အသုံးပြုခွင့်ပေးပါတယ်။ ဒီလိုခေါ်သုံးနိုင်တာ `Facade` class ကြောင့်ဖြစ်ပါတယ်။ Laravel ရဲ့ Facade တွေ နဲ့ သင်ကိုယ်ပိုင်ဆောက်ထားတဲ့ Facade တွေအားလုံးဟာ `Facade` class ကို Extend ပြုလုပ်ရပါတယ်။ +Throughout the Laravel documentation, many of the examples will use facades to demonstrate various features of the framework. -သင့်ကိုယ်ပိုင် Facade class ဆောက်တော့မယ်ဆိုရင် `getFacadeAccessor` ဆိုတဲ့ method ကိုပဲ implement လုပ်ဖို့လိုပါမယ်။ `getFacadeAccessor` က Container ထဲကနေ ဘယ်ဟာကိုသုံးရမယ်လို့ ဆုံးဖြတ်ပေးပါတယ်။ သင့်ကိုယ်ပိုင် Facade ကနေ Resolved လုပ်ပြီးသား object ထဲကိုရွှေ့ပြောင်းဖို့အတွက် အခြေခံ `Facade` class မှာတော့ `__callStatic()` ဆိုတဲ့ magic-method ကိုသုံးထားပါတယ်။ + +## When To Use Facades -ဒါ့ကြောင့် သင့်အနေနဲ့ `Cache::get` လိုမျိုး Facade တစ်ခုကို ခေါ်မယ်ဆိုရင် Laravel က Cache manager class ကို IoC container ထဲကနေဆွဲထုတ်ပြီး သူထဲက `get` method ကိုခေါ်ပေးပါတယ်။ နည်းပညာအခေါ်အဝေါ်အရဆိုရင်တော Laravel Facades တွေဆိုတာ Ioc container တွေကို service locator တစ်ခုအနေနဲ့အသုံးပြုနိုင်တဲ့ ရေး/ဖတ်/မှတ်ရလွယ်ကူသော syntax ဖြစ်ပါတယ်။ +Facades have many benefits. They provide a terse, memorable syntax that allows you to use Laravel's features without remembering long class names that must be injected or configured manually. Furthermore, because of their unique usage of PHP's dynamic methods, they are easy to test. - -## လက်တွေ့အသုံးချခြင်း +However, some care must be taken when using facades. The primary danger of facades is class scope creep. Since facades are so easy to use and do not require injection, it can be easy to let your classes continue to grow and use many facades in a single class. Using dependency injection, this potential is mitigated by the visual feedback a large constructor gives you that your class is growing too large. So, when using facades, pay special attention to the size of your class so that its scope of responsibility stays narrow. -အောက်ကအတိုင်းဆိုရင် ၊ Laravel cache system ကို ခေါ်တာပါ။ သာမာန်အပေါ်ယံအတိုင်း ကြည့်လိုက်မယ်ဆိုရင်တော့ `Cache` class ထဲက `get` ဆိုတဲ့ static method တစ်ခုကို ခေါ်လိုက်တယ်လို့ထင်ရပါတယ်။ +> {tip} When building a third-party package that interacts with Laravel, it's better to inject [Laravel contracts](/docs/{{version}}/contracts) instead of using facades. Since packages are built outside of Laravel itself, you will not have access to Laravel's facade testing helpers. - $value = Cache::get('key'); + +### Facades Vs. Dependency Injection -ဒါပေမယ့် `Illuminate\Support\Facades\Cache` class ကိုကြည့်လိုက်မယ်ဆိုရင် `get` ဆိုတဲ့ static method လုံးဝမရှိပါဘူး +One of the primary benefits of dependency injection is the ability to swap implementations of the injected class. This is useful during testing since you can inject a mock or stub and assert that various methods were called on the stub. - class Cache extends Facade { +Typically, it would not be possible to mock or stub a truly static class method. However, since facades use dynamic methods to proxy method calls to objects resolved from the service container, we actually can test facades just as we would test an injected class instance. For example, given the following route: - /** - * Get the registered name of the component. - * - * @return string - */ - protected static function getFacadeAccessor() { return 'cache'; } + use Illuminate\Support\Facades\Cache; - } + Route::get('/cache', function () { + return Cache::get('key'); + }); -Cache class က `Facade` class ကို extend လုပ်ထားပြီး `getFacadeAccessor()` ဆိုတာပဲရှိပါတယ်။ အဲဒီ Method ရဲ့တာဝန်က IoC နာမည်ကို return လုပ်ပေးယုံပါပဲ။ +We can write the following test to verify that the `Cache::get` method was called with the argument we expected: -User က `Cache` facade ထဲက ဘယ် static method ကိုမဆို သုံးလိုက်မယ်ဆိုတာနဲ့ ၊ Laravel က IoC container ထဲကနေ `cache` ကိုခေါ်ပြီး ၊ ကိုယ်လိုချင်တဲ့ method (အခုအတိုင်းဆို `get`) ကို run ပေးပါတယ်။ + use Illuminate\Support\Facades\Cache; -ဒါ့ကြောင့် ၊ ကျွန်တော်တို့သုံးထားတဲ့ `Cache::get` ရဲ့ နောက်ကွယ်မှာက အောက်ကအတိုင်းရှိနေပါမယ်။ + /** + * A basic functional test example. + * + * @return void + */ + public function testBasicExample() + { + Cache::shouldReceive('get') + ->with('key') + ->andReturn('value'); - $value = $app->make('cache')->get('key'); + $this->visit('/cache') + ->see('value'); + } - -## ကိုယ်ပိုင် Facades တည်ဆောက်ခြင်း + +### Facades Vs. Helper Functions -Creating a facade for your own application or package is simple. You only need 3 things: -ကိုယ့် application (ဒါမှမဟုတ်) package အတွက် ကိုယ်ပိုင် facade ဆောက်ရတာလွယ်ကူပါတယ်။ အဆင့် ၃ ဆင့်ပဲလိုပါတယ် : +In addition to facades, Laravel includes a variety of "helper" functions which can perform common tasks like generating views, firing events, dispatching jobs, or sending HTTP responses. Many of these helper functions perform the same function as a corresponding facade. For example, this facade call and helper call are equivalent: -- An IoC binding -- facade class တစ်ခု -- facade ကိုယ် ခေါ်မယ့် Alia သတ်မှတ်ပေးရန် + return View::make('profile'); -ဥပမာတစ်ခုလောက် ကြည့်ကြပါမယ်။ ကျွန်တော်တို့မှာ `PaymentGateway\Payment` ဆိုတဲ့ class တစ်ခုရှိမယ်ဆိုကြပါစို့ + return view('profile'); - namespace PaymentGateway; +There is absolutely no practical difference between facades and helper functions. When using helper functions, you may still test them exactly as you would the corresponding facade. For example, given the following route: - class Payment { + Route::get('/cache', function () { + return cache('key'); + }); - public function process() - { - // - } +Under the hood, the `cache` helper is going to call the `get` method on the class underlying the `Cache` facade. So, even though we are using the helper function, we can write the following test to verify that the method was called with the argument we expected: - } + use Illuminate\Support\Facades\Cache; -ဒီ class က `app/models` directory ထဲမှာဖြစ်ဖြစ် (ဒါမှမဟုတ်) တစ်ခြား Composer က auto-load ပြုလုပ်နိုင်တဲ့ မည်သည့်နေရာတွင်မဆို တည်ရှိနိုင်ပါတယ်။ + /** + * A basic functional test example. + * + * @return void + */ + public function testBasicExample() + { + Cache::shouldReceive('get') + ->with('key') + ->andReturn('value'); -IoC container ထဲအဲဒီ class ကို ထည့်ပေးဖို့အတွက် bind လုပ်ဖို့လိုပါမယ်။ + $this->visit('/cache') + ->see('value'); + } - App::bind('payment', function() - { - return new \PaymentGateway\Payment; - }); + +## How Facades Work -ဒီ bind လုပ်ထားတာကို Register လုပ်ဖို့အတွက် အကောင်းဆုံးနည်းကတော့ `PaymentServiceProvider` ဆိုပြီး [service provider](ioc#service-providers.md) တစ်ခုဆောက်ပြီးတော့ အပေါ်က bind လုပ်ထားတာကို `register` ဆိုတဲ့ method ထဲ ထည့်ပေးလိုက်တာပါ။ အခုဆောက်ထားတဲ့ Service Provider ကို Laravel က load လုပ်ဖို့ဆိုရင်တော့ `app/config/app.php` ထဲမှာ သတ်မှတ်ပေးဖို့လိုပါမယ်။ +In a Laravel application, a facade is a class that provides access to an object from the container. The machinery that makes this work is in the `Facade` class. Laravel's facades, and any custom facades you create, will extend the base `Illuminate\Support\Facades\Facade` class. -Next, we can create our own facade class: -နောက်တစ်ဆင့်မှာတော့ ကိုယ်ပိုင် facade class ဆောက်နိုင်ပါပြီ - +The `Facade` base class makes use of the `__callStatic()` magic-method to defer calls from your facade to an object resolved from the container. In the example below, a call is made to the Laravel cache system. By glancing at this code, one might assume that the static method `get` is being called on the `Cache` class: - use Illuminate\Support\Facades\Facade; + $user]); + } + } - Payment::process(); +Notice that near the top of the file we are "importing" the `Cache` facade. This facade serves as a proxy to accessing the underlying implementation of the `Illuminate\Contracts\Cache\Factory` interface. Any calls we make using the facade will be passed to the underlying instance of Laravel's cache service. -### Aliases တွေကို Auto-Load လုပ်တဲ့အခါ သတိထားစရာများ +If we look at that `Illuminate\Support\Facades\Cache` class, you'll see that there is no static method `get`: -[PHP က type hint မသက်မှတ်ပေးထားတဲ့ class တွေကို autload လုပ်ပေးမှာမဟုတ်တဲ့အတွက်](https://bugs.php.net/bug.php?id=39003) `Aliases` array ထဲမှာ ရှိတဲ့ Class တွေကို တစ်ချို့သော instance တွေမှာ သုံးလို့မရပါဘူး။ `\ServiceWrapper\ApiTimeoutException` ကို `ApiTimeoutException` လို့ Alia လုပ်ထားလိုက်မယ်ဆိုရင် `\ServiceWrapper` namespace ရဲ့အပြင်ဖက်မှာ `catch(ApiTimeoutException $e)` လို့ခေါ်မယ်ဆိုရင် thrown လုပ်လိုက်ပေမယ့် ဘယ်တော့မှ catch လုပ်လို့မရပါဘူး။ ဒီလိုပြဿနာမျိုးကိုပဲ Model တွေမှာလဲ ကြုံတွေ့နိုင်ပါတယ်။ တစ်ခုတည်းသော ဖြေရှင်းနည်းကတော့ Alias တွေမသတ်မှတ်ဘဲ file ရဲ့အပေါ်ဆုံးမှာ `use` ဆိုပြီးသတ်မှတ်ပြီးသုံးတာပါပဲ။ + class Cache extends Facade + { + /** + * Get the registered name of the component. + * + * @return string + */ + protected static function getFacadeAccessor() { return 'cache'; } + } - - -## Facades တွေကို Mock ပြုလုပ်ပေးခြင်း -Facade တွေ အဓိကရှိနေရခြင်းရဲ့အကြောင်းရင်းကတော့ Test လွယ်လွယ်ကူကူလုပ်နိုင်ဖို့ပဲဖြစ်ပါတယ်။ Mock လုပ်တဲ့အပိုင်းကိုတော့ [mocking facades](testing#mocking-facades.md) မှာ ပြည့်ပြည့်စုံစုံ ဖော်ပြပေးထားပါတယ်။ +Instead, the `Cache` facade extends the base `Facade` class and defines the method `getFacadeAccessor()`. This method's job is to return the name of a service container binding. When a user references any static method on the `Cache` facade, Laravel resolves the `cache` binding from the [service container](/docs/{{version}}/container) and runs the requested method (in this case, `get`) against that object. -## Facade Class ကိုကား +## Facade Class Reference -အောက်ကဇယားမှာတော့ ရှိသမျှ Facade တွေနဲ့ သူရဲ့နောက်ကွယ်က class တွေကို ဖော်ပြပေးထားပါတယ်။ API Documentation ထဲကို သက်ဆိုင်ရာ နေရာလိုက်လဲ ချိတ်ပေးထားပါတယ်။ [IoC binding](ioc.md) key ရှိတဲ့ Facade တွေကိုလဲ သူ့ key တွေရေးပေးထားပါတယ်။ +Below you will find every facade and its underlying class. This is a useful tool for quickly digging into the API documentation for a given facade root. The [service container binding](/docs/{{version}}/container) key is also included where applicable. -Facade | Class | IoC Binding +Facade | Class | Service Container Binding ------------- | ------------- | ------------- -App | [Illuminate\Foundation\Application](http://laravel.com/api/4.1/Illuminate/Foundation/Application.html) | `app` -Artisan | [Illuminate\Console\Application](http://laravel.com/api/4.1/Illuminate/Console/Application.html) | `artisan` -Auth | [Illuminate\Auth\AuthManager](http://laravel.com/api/4.1/Illuminate/Auth/AuthManager.html) | `auth` -Auth (Instance) | [Illuminate\Auth\Guard](http://laravel.com/api/4.1/Illuminate/Auth/Guard.html) | -Blade | [Illuminate\View\Compilers\BladeCompiler](http://laravel.com/api/4.1/Illuminate/View/Compilers/BladeCompiler.html) | `blade.compiler` -Cache | [Illuminate\Cache\Repository](http://laravel.com/api/4.1/Illuminate/Cache/Repository.html) | `cache` -Config | [Illuminate\Config\Repository](http://laravel.com/api/4.1/Illuminate/Config/Repository.html) | `config` -Cookie | [Illuminate\Cookie\CookieJar](http://laravel.com/api/4.1/Illuminate/Cookie/CookieJar.html) | `cookie` -Crypt | [Illuminate\Encryption\Encrypter](http://laravel.com/api/4.1/Illuminate/Encryption/Encrypter.html) | `encrypter` -DB | [Illuminate\Database\DatabaseManager](http://laravel.com/api/4.1/Illuminate/Database/DatabaseManager.html) | `db` -DB (Instance) | [Illuminate\Database\Connection](http://laravel.com/api/4.1/Illuminate/Database/Connection.html) | -Event | [Illuminate\Events\Dispatcher](http://laravel.com/api/4.1/Illuminate/Events/Dispatcher.html) | `events` -File | [Illuminate\Filesystem\Filesystem](http://laravel.com/api/4.1/Illuminate/Filesystem/Filesystem.html) | `files` -Form | [Illuminate\Html\FormBuilder](http://laravel.com/api/4.1/Illuminate/Html/FormBuilder.html) | `form` -Hash | [Illuminate\Hashing\HasherInterface](http://laravel.com/api/4.1/Illuminate/Hashing/HasherInterface.html) | `hash` -HTML | [Illuminate\Html\HtmlBuilder](http://laravel.com/api/4.1/Illuminate/Html/HtmlBuilder.html) | `html` -Input | [Illuminate\Http\Request](http://laravel.com/api/4.1/Illuminate/Http/Request.html) | `request` -Lang | [Illuminate\Translation\Translator](http://laravel.com/api/4.1/Illuminate/Translation/Translator.html) | `translator` -Log | [Illuminate\Log\Writer](http://laravel.com/api/4.1/Illuminate/Log/Writer.html) | `log` -Mail | [Illuminate\Mail\Mailer](http://laravel.com/api/4.1/Illuminate/Mail/Mailer.html) | `mailer` -Paginator | [Illuminate\Pagination\Factory](http://laravel.com/api/4.1/Illuminate/Pagination/Factory.html) | `paginator` -Paginator (Instance) | [Illuminate\Pagination\Paginator](http://laravel.com/api/4.1/Illuminate/Pagination/Paginator.html) | -Password | [Illuminate\Auth\Reminders\PasswordBroker](http://laravel.com/api/4.1/Illuminate/Auth/Reminders/PasswordBroker.html) | `auth.reminder` -Queue | [Illuminate\Queue\QueueManager](http://laravel.com/api/4.1/Illuminate/Queue/QueueManager.html) | `queue` -Queue (Instance) | [Illuminate\Queue\QueueInterface](http://laravel.com/api/4.1/Illuminate/Queue/QueueInterface.html) | -Queue (Base Class) | [Illuminate\Queue\Queue](http://laravel.com/api/4.1/Illuminate/Queue/Queue.html) | -Redirect | [Illuminate\Routing\Redirector](http://laravel.com/api/4.1/Illuminate/Routing/Redirector.html) | `redirect` -Redis | [Illuminate\Redis\Database](http://laravel.com/api/4.1/Illuminate/Redis/Database.html) | `redis` -Request | [Illuminate\Http\Request](http://laravel.com/api/4.1/Illuminate/Http/Request.html) | `request` -Response | [Illuminate\Support\Facades\Response](http://laravel.com/api/4.1/Illuminate/Support/Facades/Response.html) | -Route | [Illuminate\Routing\Router](http://laravel.com/api/4.1/Illuminate/Routing/Router.html) | `router` -Schema | [Illuminate\Database\Schema\Blueprint](http://laravel.com/api/4.1/Illuminate/Database/Schema/Blueprint.html) | -Session | [Illuminate\Session\SessionManager](http://laravel.com/api/4.1/Illuminate/Session/SessionManager.html) | `session` -Session (Instance) | [Illuminate\Session\Store](http://laravel.com/api/4.1/Illuminate/Session/Store.html) | -SSH | [Illuminate\Remote\RemoteManager](http://laravel.com/api/4.1/Illuminate/Remote/RemoteManager.html) | `remote` -SSH (Instance) | [Illuminate\Remote\Connection](http://laravel.com/api/4.1/Illuminate/Remote/Connection.html) | -URL | [Illuminate\Routing\UrlGenerator](http://laravel.com/api/4.1/Illuminate/Routing/UrlGenerator.html) | `url` -Validator | [Illuminate\Validation\Factory](http://laravel.com/api/4.1/Illuminate/Validation/Factory.html) | `validator` -Validator (Instance) | [Illuminate\Validation\Validator](http://laravel.com/api/4.1/Illuminate/Validation/Validator.html) -View | [Illuminate\View\Factory](http://laravel.com/api/4.1/Illuminate/View/Factory.html) | `view` -View (Instance) | [Illuminate\View\View](http://laravel.com/api/4.1/Illuminate/View/View.html) | \ No newline at end of file +App | [Illuminate\Foundation\Application](https://laravel.com/api/{{version}}/Illuminate/Foundation/Application.html) | `app` +Artisan | [Illuminate\Contracts\Console\Kernel](https://laravel.com/api/{{version}}/Illuminate/Contracts/Console/Kernel.html) | `artisan` +Auth | [Illuminate\Auth\AuthManager](https://laravel.com/api/{{version}}/Illuminate/Auth/AuthManager.html) | `auth` +Blade | [Illuminate\View\Compilers\BladeCompiler](https://laravel.com/api/{{version}}/Illuminate/View/Compilers/BladeCompiler.html) | `blade.compiler` +Bus | [Illuminate\Contracts\Bus\Dispatcher](https://laravel.com/api/{{version}}/Illuminate/Contracts/Bus/Dispatcher.html) |   +Cache | [Illuminate\Cache\Repository](https://laravel.com/api/{{version}}/Illuminate/Cache/Repository.html) | `cache` +Config | [Illuminate\Config\Repository](https://laravel.com/api/{{version}}/Illuminate/Config/Repository.html) | `config` +Cookie | [Illuminate\Cookie\CookieJar](https://laravel.com/api/{{version}}/Illuminate/Cookie/CookieJar.html) | `cookie` +Crypt | [Illuminate\Encryption\Encrypter](https://laravel.com/api/{{version}}/Illuminate/Encryption/Encrypter.html) | `encrypter` +DB | [Illuminate\Database\DatabaseManager](https://laravel.com/api/{{version}}/Illuminate/Database/DatabaseManager.html) | `db` +DB (Instance) | [Illuminate\Database\Connection](https://laravel.com/api/{{version}}/Illuminate/Database/Connection.html) |   +Event | [Illuminate\Events\Dispatcher](https://laravel.com/api/{{version}}/Illuminate/Events/Dispatcher.html) | `events` +File | [Illuminate\Filesystem\Filesystem](https://laravel.com/api/{{version}}/Illuminate/Filesystem/Filesystem.html) | `files` +Gate | [Illuminate\Contracts\Auth\Access\Gate](https://laravel.com/api/{{version}}/Illuminate/Contracts/Auth/Access/Gate.html) |   +Hash | [Illuminate\Contracts\Hashing\Hasher](https://laravel.com/api/{{version}}/Illuminate/Contracts/Hashing/Hasher.html) | `hash` +Lang | [Illuminate\Translation\Translator](https://laravel.com/api/{{version}}/Illuminate/Translation/Translator.html) | `translator` +Log | [Illuminate\Log\Writer](https://laravel.com/api/{{version}}/Illuminate/Log/Writer.html) | `log` +Mail | [Illuminate\Mail\Mailer](https://laravel.com/api/{{version}}/Illuminate/Mail/Mailer.html) | `mailer` +Notification | [Illuminate\Notifications\ChannelManager](https://laravel.com/api/{{version}}/Illuminate/Notifications/ChannelManager.html) |   +Password | [Illuminate\Auth\Passwords\PasswordBrokerManager](https://laravel.com/api/{{version}}/Illuminate/Auth/Passwords/PasswordBrokerManager.html) | `auth.password` +Queue | [Illuminate\Queue\QueueManager](https://laravel.com/api/{{version}}/Illuminate/Queue/QueueManager.html) | `queue` +Queue (Instance) | [Illuminate\Contracts\Queue\Queue](https://laravel.com/api/{{version}}/Illuminate/Contracts/Queue/Queue.html) | `queue` +Queue (Base Class) | [Illuminate\Queue\Queue](https://laravel.com/api/{{version}}/Illuminate/Queue/Queue.html) |   +Redirect | [Illuminate\Routing\Redirector](https://laravel.com/api/{{version}}/Illuminate/Routing/Redirector.html) | `redirect` +Redis | [Illuminate\Redis\Database](https://laravel.com/api/{{version}}/Illuminate/Redis/Database.html) | `redis` +Request | [Illuminate\Http\Request](https://laravel.com/api/{{version}}/Illuminate/Http/Request.html) | `request` +Response | [Illuminate\Contracts\Routing\ResponseFactory](https://laravel.com/api/{{version}}/Illuminate/Contracts/Routing/ResponseFactory.html) |   +Route | [Illuminate\Routing\Router](https://laravel.com/api/{{version}}/Illuminate/Routing/Router.html) | `router` +Schema | [Illuminate\Database\Schema\Blueprint](https://laravel.com/api/{{version}}/Illuminate/Database/Schema/Blueprint.html) |   +Session | [Illuminate\Session\SessionManager](https://laravel.com/api/{{version}}/Illuminate/Session/SessionManager.html) | `session` +Session (Instance) | [Illuminate\Session\Store](https://laravel.com/api/{{version}}/Illuminate/Session/Store.html) |   +Storage | [Illuminate\Contracts\Filesystem\Factory](https://laravel.com/api/{{version}}/Illuminate/Contracts/Filesystem/Factory.html) | `filesystem` +URL | [Illuminate\Routing\UrlGenerator](https://laravel.com/api/{{version}}/Illuminate/Routing/UrlGenerator.html) | `url` +Validator | [Illuminate\Validation\Factory](https://laravel.com/api/{{version}}/Illuminate/Validation/Factory.html) | `validator` +Validator (Instance) | [Illuminate\Validation\Validator](https://laravel.com/api/{{version}}/Illuminate/Validation/Validator.html) |   +View | [Illuminate\View\Factory](https://laravel.com/api/{{version}}/Illuminate/View/Factory.html) | `view` +View (Instance) | [Illuminate\View\View](https://laravel.com/api/{{version}}/Illuminate/View/View.html) |   diff --git a/filesystem.md b/filesystem.md new file mode 100644 index 0000000..3de773b --- /dev/null +++ b/filesystem.md @@ -0,0 +1,367 @@ +# Filesystem / Cloud Storage + +- [Introduction](#introduction) +- [Configuration](#configuration) + - [The Public Disk](#the-public-disk) + - [The Local Driver](#the-local-driver) + - [Driver Prerequisites](#driver-prerequisites) +- [Obtaining Disk Instances](#obtaining-disk-instances) +- [Retrieving Files](#retrieving-files) + - [File URLs](#file-urls) + - [File Metadata](#file-metadata) +- [Storing Files](#storing-files) + - [File Uploads](#file-uploads) + - [File Visibility](#file-visibility) +- [Deleting Files](#deleting-files) +- [Directories](#directories) +- [Custom Filesystems](#custom-filesystems) + + +## Introduction + +Laravel provides a powerful filesystem abstraction thanks to the wonderful [Flysystem](https://github.com/thephpleague/flysystem) PHP package by Frank de Jonge. The Laravel Flysystem integration provides simple to use drivers for working with local filesystems, Amazon S3, and Rackspace Cloud Storage. Even better, it's amazingly simple to switch between these storage options as the API remains the same for each system. + + +## Configuration + +The filesystem configuration file is located at `config/filesystems.php`. Within this file you may configure all of your "disks". Each disk represents a particular storage driver and storage location. Example configurations for each supported driver are included in the configuration file. So, simply modify the configuration to reflect your storage preferences and credentials. + +Of course, you may configure as many disks as you like, and may even have multiple disks that use the same driver. + + +### The Public Disk + +The `public` disk is intended for files that are going to be publicly accessible. By default, the `public` disk uses the `local` driver and stores these files in `storage/app/public`. To make them accessible from the web, you should create a symbolic link from `public/storage` to `storage/app/public`. This convention will keep your publicly accessible files in one directory that can be easily shared across deployments when using zero down-time deployment systems like [Envoyer](https://envoyer.io). + +To create the symbolic link, you may use the `storage:link` Artisan command: + + php artisan storage:link + +Of course, once a file has been stored and the symbolic link has been created, you can create a URL to the files using the `asset` helper: + + echo asset('storage/file.txt'); + + +### The Local Driver + +When using the `local` driver, all file operations are relative to the `root` directory defined in your configuration file. By default, this value is set to the `storage/app` directory. Therefore, the following method would store a file in `storage/app/file.txt`: + + Storage::disk('local')->put('file.txt', 'Contents'); + + +### Driver Prerequisites + +#### Composer Packages + +Before using the S3 or Rackspace drivers, you will need to install the appropriate package via Composer: + +- Amazon S3: `league/flysystem-aws-s3-v3 ~1.0` +- Rackspace: `league/flysystem-rackspace ~1.0` + +#### S3 Driver Configuration + +The S3 driver configuration information is located in your `config/filesystems.php` configuration file. This file contains an example configuration array for an S3 driver. You are free to modify this array with your own S3 configuration and credentials. + +#### FTP Driver Configuration + +Laravel's Flysystem integrations works great with FTP; however, a sample configuration is not included with the framework's default `filesystems.php` configuration file. If you need to configure a FTP filesystem, you may use the example configuration below: + + 'ftp' => [ + 'driver' => 'ftp', + 'host' => 'ftp.example.com', + 'username' => 'your-username', + 'password' => 'your-password', + + // Optional FTP Settings... + // 'port' => 21, + // 'root' => '', + // 'passive' => true, + // 'ssl' => true, + // 'timeout' => 30, + ], + +#### Rackspace Driver Configuration + +Laravel's Flysystem integrations works great with Rackspace; however, a sample configuration is not included with the framework's default `filesystems.php` configuration file. If you need to configure a Rackspace filesystem, you may use the example configuration below: + + 'rackspace' => [ + 'driver' => 'rackspace', + 'username' => 'your-username', + 'key' => 'your-key', + 'container' => 'your-container', + 'endpoint' => 'https://identity.api.rackspacecloud.com/v2.0/', + 'region' => 'IAD', + 'url_type' => 'publicURL', + ], + + +## Obtaining Disk Instances + +The `Storage` facade may be used to interact with any of your configured disks. For example, you may use the `put` method on the facade to store an avatar on the default disk. If you call methods on the `Storage` facade without first calling the `disk` method, the method call will automatically be passed to the default disk: + + use Illuminate\Support\Facades\Storage; + + Storage::put('avatars/1', $fileContents); + +If your applications interacts with multiple disks, you may use the `disk` method on the `Storage` facade to work with files on a particular disk: + + Storage::disk('s3')->put('avatars/1', $fileContents); + + +## Retrieving Files + +The `get` method may be used to retrieve the contents of a file. The raw string contents of the file will be returned by the method. Remember, all file paths should be specified relative to the "root" location configured for the disk: + + $contents = Storage::get('file.jpg'); + +The `exists` method may be used to determine if a file exists on the disk: + + $exists = Storage::disk('s3')->exists('file.jpg'); + + +### File URLs + +When using the `local` or `s3` drivers, you may use the `url` method to get the URL for the given file. If you are using the `local` driver, this will typically just prepend `/storage` to the given path and return a relative URL to the file. If you are using the `s3` driver, the fully qualified remote URL will be returned: + + use Illuminate\Support\Facades\Storage; + + $url = Storage::url('file1.jpg'); + +> {note} Remember, if you are using the `local` driver, all files that should be publicly accessible should be placed in the `storage/app/public` directory. Furthermore, you should [create a symbolic link](#the-public-disk) at `public/storage` which points to the `storage/app/public` directory. + +#### Local URL Host Customization + +If you would like to pre-define the host for files stored on a disk using the `local` driver, you may add a `url` option to the disk's configuration array: + + 'public' => [ + 'driver' => 'local', + 'root' => storage_path('app/public'), + 'url' => env('APP_URL').'/storage', + 'visibility' => 'public', + ], + + +### File Metadata + +In addition to reading and writing files, Laravel can also provide information about the files themselves. For example, the `size` method may be used to get the size of the file in bytes: + + use Illuminate\Support\Facades\Storage; + + $size = Storage::size('file1.jpg'); + +The `lastModified` method returns the UNIX timestamp of the last time the file was modified: + + $time = Storage::lastModified('file1.jpg'); + + +## Storing Files + +The `put` method may be used to store raw file contents on a disk. You may also pass a PHP `resource` to the `put` method, which will use Flysystem's underlying stream support. Using streams is greatly recommended when dealing with large files: + + use Illuminate\Support\Facades\Storage; + + Storage::put('file.jpg', $contents); + + Storage::put('file.jpg', $resource); + +#### Automatic Streaming + +If you would like Laravel to automatically manage streaming a given file to your storage location, you may use the `putFile` or `putFileAs` method. This method accepts either a `Illuminate\Http\File` or `Illuminate\Http\UploadedFile` instance and will automatically stream the file to your desire location: + + use Illuminate\Http\File; + + // Automatically generate a unique ID for file name... + Storage::putFile('photos', new File('/path/to/photo')); + + // Manually specify a file name... + Storage::putFileAs('photos', new File('/path/to/photo'), 'photo.jpg'); + +There are a few important things to note about the `putFile` method. Note that we only specified a directory name, not a file name. By default, the `putFile` method will generate a unique ID to serve as the file name. The path to the file will be returned by the `putFile` method so you can store the path, including the generated file name, in your database. + +The `putFile` and `putFileAs` methods also accept an argument to specify the "visibility" of the stored file. This is particularly useful if you are storing the file on a cloud disk such as S3 and would like the file to be publicly accessible: + + Storage::putFile('photos', new File('/path/to/photo'), 'public'); + +#### Prepending & Appending To Files + +The `prepend` and `append` methods allow you to write to the beginning or end of a file: + + Storage::prepend('file.log', 'Prepended Text'); + + Storage::append('file.log', 'Appended Text'); + +#### Copying & Moving Files + +The `copy` method may be used to copy an existing file to a new location on the disk, while the `move` method may be used to rename or move an existing file to a new location: + + Storage::copy('old/file1.jpg', 'new/file1.jpg'); + + Storage::move('old/file1.jpg', 'new/file1.jpg'); + + +### File Uploads + +In web applications, one of the most common use-cases for storing files is storing user uploaded files such as profile pictures, photos, and documents. Laravel makes it very easy to store uploaded files using the `store` method on an uploaded file instance. Simply call the `store` method with the path at which you wish to store the uploaded file: + + file('avatar')->store('avatars'); + + return $path; + } + } + +There are a few important things to note about this example. Note that we only specified a directory name, not a file name. By default, the `store` method will generate a unique ID to serve as the file name. The path to the file will be returned by the `store` method so you can store the path, including the generated file name, in your database. + +You may also call the `putFile` method on the `Storage` facade to perform the same file manipulation as the example above: + + $path = Storage::putFile('avatars', $request->file('avatar')); + +#### Specifying A File Name + +If you would not like a file name to be automatically assigned to your stored file, you may use the `storeAs` method, which receives the path, the file name, and the (optional) disk as its arguments: + + $path = $request->file('avatar')->storeAs( + 'avatars', $request->user()->id + ); + +Of course, you may also use the `putFileAs` method on the `Storage` facade, which will perform the same file manipulation as the example above: + + $path = Storage::putFileAs( + 'avatars', $request->file('avatar'), $request->user()->id + ); + +#### Specifying A Disk + +By default, this method will use your default disk. If you would like to specify another disk, pass the disk name as the second argument to the `store` method: + + $path = $request->file('avatar')->store( + 'avatars/'.$request->user()->id, 's3' + ); + + +### File Visibility + +In Laravel's Flysystem integration, "visibility" is an abstraction of file permissions across multiple platforms. Files may either be declared `public` or `private`. When a file is declared `public`, you are indicating that the file should generally be accessible to others. For example, when using the S3 driver, you may retrieve URLs for `public` files. + +You can set the visibility when setting the file via the `put` method: + + use Illuminate\Support\Facades\Storage; + + Storage::put('file.jpg', $contents, 'public'); + +If the file has already been stored, its visibility can be retrieved and set via the `getVisibility` and `setVisibility` methods: + + $visibility = Storage::getVisibility('file.jpg'); + + Storage::setVisibility('file.jpg', 'public') + + +## Deleting Files + +The `delete` method accepts a single filename or an array of files to remove from the disk: + + use Illuminate\Support\Facades\Storage; + + Storage::delete('file.jpg'); + + Storage::delete(['file1.jpg', 'file2.jpg']); + + +## Directories + +#### Get All Files Within A Directory + +The `files` method returns an array of all of the files in a given directory. If you would like to retrieve a list of all files within a given directory including all sub-directories, you may use the `allFiles` method: + + use Illuminate\Support\Facades\Storage; + + $files = Storage::files($directory); + + $files = Storage::allFiles($directory); + +#### Get All Directories Within A Directory + +The `directories` method returns an array of all the directories within a given directory. Additionally, you may use the `allDirectories` method to get a list of all directories within a given directory and all of its sub-directories: + + $directories = Storage::directories($directory); + + // Recursive... + $directories = Storage::allDirectories($directory); + +#### Create A Directory + +The `makeDirectory` method will create the given directory, including any needed sub-directories: + + Storage::makeDirectory($directory); + +#### Delete A Directory + +Finally, the `deleteDirectory` may be used to remove a directory and all of its files: + + Storage::deleteDirectory($directory); + + +## Custom Filesystems + +Laravel's Flysystem integration provides drivers for several "drivers" out of the box; however, Flysystem is not limited to these and has adapters for many other storage systems. You can create a custom driver if you want to use one of these additional adapters in your Laravel application. + +In order to set up the custom filesystem you will need to create a [service provider](/docs/{{version}}/providers) such as `DropboxServiceProvider`. In the provider's `boot` method, you may use the `Storage` facade's `extend` method to define the custom driver: + + +## Introduction + +While Laravel does not dictate which JavaScript or CSS pre-processors you use, it does provide a basic starting point using [Bootstrap](https://getbootstrap.com/) and [Vue](https://vuejs.org) that will be helpful for many applications. By default, Laravel uses [NPM](https://www.npmjs.org) to install both of these frontend packages. + +#### CSS + +[Laravel Mix](/docs/{{version}}/mix) provides a clean, expressive API over compiling SASS or Less, which are extensions of plain CSS that add variables, mixins, and other powerful features that make working with CSS much more enjoyable. + +In this document, we will briefly discuss CSS compilation in general; however, you should consult the full [Laravel Mix documentation](/docs/{{version}}/mix) for more information on compiling SASS or Less. + +#### JavaScript + +Laravel does not require you to use a specific JavaScript framework or library to build your applications. In fact, you don't have to use JavaScript at all. However, Laravel does include some basic scaffolding to make it easier to get started writing modern JavaScript using the [Vue](https://vuejs.org) library. Vue provides an expressive API for building robust JavaScript applications using components. + + +## Writing CSS + +The Laravel `package.json` file includes the `bootstrap-sass` package to help you get started prototyping your application's frontend using Bootstrap. However, feel free to add or remove packages from the `package.json` file as needed for your own application. You are not required to use the Bootstrap framework to build your Laravel application - it is simply provided as a good starting point for those who choose to use it. + +Before compiling your CSS, install your project's frontend dependencies using NPM: + + npm install + +Once the dependencies have been installed using `npm install`, you can compile your SASS files to plain CSS using [Laravel Mix](/docs/{{version}}/mix#working-with-stylesheets). The `npm run dev` command will process the instructions in your `webpack.mix.js` file. Typically, your compiled CSS will be placed in the `public/css` directory: + + npm run dev + +The default `webpack.mix.js` included with Laravel will compile the `resources/assets/sass/app.scss` SASS file. This `app.scss` file imports a file of SASS variables and loads Bootstrap, which provides a good starting point for most applications. Feel free to customize the `app.scss` file however you wish or even use an entirely different pre-processor by [configuring Laravel Mix](/docs/{{version}}/mix). + + +## Writing JavaScript + +All of the JavaScript dependencies required by your application can be found in the `package.json` file in the project's root directory. This file is similar to a `composer.json` file except it specifies JavaScript dependencies instead of PHP dependencies. You can install these dependencies using the [Node package manager (NPM)](https://www.npmjs.org): + + npm install + +By default, the Laravel `package.json` file includes a few packages such as `vue` and `axios` to help you get started building your JavaScript application. Feel free to add or remove from the `package.json` file as needed for your own application. + +Once the packages are installed, you can use the `npm run dev` command to [compile your assets](/docs/{{version}}/mix). Webpack is a module bundler for modern JavaScript applications. When you run the `npm run dev` command, Webpack will execute the instructions in your `webpack.mix.js` file: + + npm run dev + +By default, the Laravel `webpack.mix.js` file compiles your SASS and the `resources/assets/js/app.js` file. Within the `app.js` file you may register your Vue components or, if you prefer a different framework, configure your own JavaScript application. Your compiled JavaScript will typically be placed in the `public/js` directory. + +> {tip} The `app.js` file will load the `resources/assets/js/bootstrap.js` file which bootstraps and configures Vue, Axios, jQuery, and all other JavaScript dependencies. If you have additional JavaScript dependencies to configure, you may do so in this file. + + +### Writing Vue Components + +By default, fresh Laravel applications contain an `Example.vue` Vue component located in the `resources/assets/js/components` directory. The `Example.vue` file is an example of a [single file Vue component](https://vuejs.org/guide/single-file-components) which defines its JavaScript and HTML template in the same file. Single file components provide a very convenient approach to building JavaScript driven applications. The example component is registered in your `app.js` file: + + Vue.component('example', require('./components/Example.vue')); + +To use the component in your application, you may simply drop it into one of your HTML templates. For example, after running the `make:auth` Artisan command to scaffold your application's authentication and registration screens, you could drop the component into the `home.blade.php` Blade template: + + @extends('layouts.app') + + @section('content') + + @endsection + +> {tip} Remember, you should run the `npm run dev` command each time you change a Vue component. Or, you may run the `npm run watch` command to monitor and automatically recompile your components each time they are modified. + +Of course, if you are interested in learning more about writing Vue components, you should read the [Vue documentation](https://vuejs.org/guide/), which provides a thorough, easy-to-read overview of the entire Vue framework. diff --git a/hashing.md b/hashing.md new file mode 100644 index 0000000..6667b97 --- /dev/null +++ b/hashing.md @@ -0,0 +1,58 @@ +# Hashing + +- [Introduction](#introduction) +- [Basic Usage](#basic-usage) + + +## Introduction + +The Laravel `Hash` [facade](/docs/{{version}}/facades) provides secure Bcrypt hashing for storing user passwords. If you are using the built-in `LoginController` and `RegisterController` classes that are included with your Laravel application, they will automatically use Bcrypt for registration and authentication. + +> {tip} Bcrypt is a great choice for hashing passwords because its "work factor" is adjustable, which means that the time it takes to generate a hash can be increased as hardware power increases. + + +## Basic Usage + +You may hash a password by calling the `make` method on the `Hash` facade: + + user()->fill([ + 'password' => Hash::make($request->newPassword) + ])->save(); + } + } + +#### Verifying A Password Against A Hash + +The `check` method allows you to verify that a given plain-text string corresponds to a given hash. However, if you are using the `LoginController` [included with Laravel](/docs/{{version}}/authentication), you will probably not need to use this directly, as this controller automatically calls this method: + + if (Hash::check('plain-text', $hashedPassword)) { + // The passwords match... + } + +#### Checking If A Password Needs To Be Rehashed + +The `needsRehash` function allows you to determine if the work factor used by the hasher has changed since the password was hashed: + + if (Hash::needsRehash($hashed)) { + $hashed = Hash::make('plain-text'); + } diff --git a/helpers.md b/helpers.md index c78ebfd..2cb4b52 100644 --- a/helpers.md +++ b/helpers.md @@ -1,414 +1,1009 @@ -# အကူ Function မ်ား - -- [Arrays](#arrays) -- [Paths](#paths) -- [Strings](#strings) -- [URLs](#urls) -- [Miscellaneous](#miscellaneous) +# Helper Functions + +- [Introduction](#introduction) +- [Available Methods](#available-methods) + + +## Introduction + +Laravel includes a variety of global "helper" PHP functions. Many of these functions are used by the framework itself; however, you are free to use them in your own applications if you find them convenient. + + +## Available Methods + + + +### Arrays + +
    + +[array_add](#method-array-add) +[array_collapse](#method-array-collapse) +[array_divide](#method-array-divide) +[array_dot](#method-array-dot) +[array_except](#method-array-except) +[array_first](#method-array-first) +[array_flatten](#method-array-flatten) +[array_forget](#method-array-forget) +[array_get](#method-array-get) +[array_has](#method-array-has) +[array_last](#method-array-last) +[array_only](#method-array-only) +[array_pluck](#method-array-pluck) +[array_prepend](#method-array-prepend) +[array_pull](#method-array-pull) +[array_set](#method-array-set) +[array_sort](#method-array-sort) +[array_sort_recursive](#method-array-sort-recursive) +[array_where](#method-array-where) +[head](#method-head) +[last](#method-last) +
    + +### Paths + +
    + +[app_path](#method-app-path) +[base_path](#method-base-path) +[config_path](#method-config-path) +[database_path](#method-database-path) +[mix](#method-mix) +[public_path](#method-public-path) +[resource_path](#method-resource-path) +[storage_path](#method-storage-path) + +
    + +### Strings + +
    + +[camel_case](#method-camel-case) +[class_basename](#method-class-basename) +[e](#method-e) +[ends_with](#method-ends-with) +[snake_case](#method-snake-case) +[str_limit](#method-str-limit) +[starts_with](#method-starts-with) +[str_contains](#method-str-contains) +[str_finish](#method-str-finish) +[str_is](#method-str-is) +[str_plural](#method-str-plural) +[str_random](#method-str-random) +[str_singular](#method-str-singular) +[str_slug](#method-str-slug) +[studly_case](#method-studly-case) +[title_case](#method-title-case) +[trans](#method-trans) +[trans_choice](#method-trans-choice) + +
    + +### URLs + +
    + +[action](#method-action) +[asset](#method-asset) +[secure_asset](#method-secure-asset) +[route](#method-route) +[secure_url](#method-secure-url) +[url](#method-url) + +
    + +### Miscellaneous + +
    + +[abort](#method-abort) +[abort_if](#method-abort-if) +[abort_unless](#method-abort-unless) +[auth](#method-auth) +[back](#method-back) +[bcrypt](#method-bcrypt) +[cache](#method-cache) +[collect](#method-collect) +[config](#method-config) +[csrf_field](#method-csrf-field) +[csrf_token](#method-csrf-token) +[dd](#method-dd) +[dispatch](#method-dispatch) +[env](#method-env) +[event](#method-event) +[factory](#method-factory) +[info](#method-info) +[logger](#method-logger) +[method_field](#method-method-field) +[old](#method-old) +[redirect](#method-redirect) +[request](#method-request) +[response](#method-response) +[retry](#method-retry) +[session](#method-session) +[value](#method-value) +[view](#method-view) + +
    + + +## Method Listing + + ## Arrays -### array_add + +#### `array_add()` {#collection-method .first-collection-method} + +The `array_add` function adds a given key / value pair to the array if the given key doesn't already exist in the array: + + $array = array_add(['name' => 'Desk'], 'price', 100); + + // ['name' => 'Desk', 'price' => 100] + + +#### `array_collapse()` {#collection-method} + +The `array_collapse` function collapses an array of arrays into a single array: + + $array = array_collapse([[1, 2, 3], [4, 5, 6], [7, 8, 9]]); + + // [1, 2, 3, 4, 5, 6, 7, 8, 9] + + +#### `array_divide()` {#collection-method} + +The `array_divide` function returns two arrays, one containing the keys, and the other containing the values of the original array: + + list($keys, $values) = array_divide(['name' => 'Desk']); + + // $keys: ['name'] + + // $values: ['Desk'] + + +#### `array_dot()` {#collection-method} + +The `array_dot` function flattens a multi-dimensional array into a single level array that uses "dot" notation to indicate depth: + + $array = array_dot(['foo' => ['bar' => 'baz']]); + + // ['foo.bar' => 'baz']; + + +#### `array_except()` {#collection-method} + +The `array_except` function removes the given key / value pairs from the array: + + $array = ['name' => 'Desk', 'price' => 100]; + + $array = array_except($array, ['price']); + + // ['name' => 'Desk'] -`array_add` function သည္ အကယ္၍ ပထမ argument array တြင္ထပ္မံေပး လုိက္ေသာ key နွင့္ တန္ဖုိး အတြဲ ရွိျပီးသား မဟုတ္ခဲ့ပါက ထုိ key နွင့္ တန္ဖုိးအတြဲအား ထပ္မံေပါင္းထည့္ေပးပါသည္။ + +#### `array_first()` {#collection-method} - $array = array('foo' => 'bar'); +The `array_first` function returns the first element of an array passing a given truth test: - $array = array_add($array, 'key', 'value'); + $array = [100, 200, 300]; -### array_divide + $value = array_first($array, function ($value, $key) { + return $value >= 150; + }); -`array_divide` function သည္ မူလ array အား key မ်ားပါ၀င္ေသာ array နွင့္ တန္ဖုိးမ်ား ပါ ၀င္ေသာ array နွစ္ခု ပါ၀င္ေသာ array အျဖစ္ return ျပန္ေပးပါသည္။ + // 200 - $array = array('foo' => 'bar'); +A default value may also be passed as the third parameter to the method. This value will be returned if no value passes the truth test: - list($keys, $values) = array_divide($array); + $value = array_first($array, $callback, $default); -### array_dot + +#### `array_flatten()` {#collection-method} -`array_dot` function သည္ dimension တစ္ခုထက္ပုိ၍ ပါ၀င္ေသာ array တစ္ခုကုိ "." သေကၤတသုံးေရးနည္းျဖင့္ အဆင့္ဆင့္ေခါ္ယူနုိင္ေသာ dimension တစ္ခုတည္း ရွိ array တစ္ခု အျဖစ္ေျပာင္းလဲေပးပါသည္။ +The `array_flatten` function will flatten a multi-dimensional array into a single level. - $array = array('foo' => array('bar' => 'baz')); -ၡ - $array = array_dot($array); + $array = ['name' => 'Joe', 'languages' => ['PHP', 'Ruby']]; - // array('foo.bar' => 'baz'); + $array = array_flatten($array); -### array_except + // ['Joe', 'PHP', 'Ruby']; -`array_except` method သည္ ေပးလုိက္ေသာ key နွင့္ တန္ဖုိး အတြဲကုိ ပထမ argument array ထံမွ ဖယ္ရွားေပးပါသည္။ + +#### `array_forget()` {#collection-method} - $array = array_except($array, array('keys', 'to', 'remove')); +The `array_forget` function removes a given key / value pair from a deeply nested array using "dot" notation: -### array_fetch + $array = ['products' => ['desk' => ['price' => 100]]]; -`array_fetch` method သည္ ပထမ argument array အတြင္းတြင္ အဆင့္ဆင့္ ညွပ္သုံးထားေသာ ေပးထားသည့္ ဒုတိယ argument နွင့္ ကုိက္ညီသည့္ nested array element မ်ားအား တစ္ဆင့္တည္း flattened လုပ္ထားေသာ array အျဖစ္ျဖင့္ return ျပန္ေပးပါသည္။ + array_forget($array, 'products.desk'); - $array = array( - array('developer' => array('name' => 'Taylor')), - array('developer' => array('name' => 'Dayle')), - ); + // ['products' => []] - $array = array_fetch($array, 'developer.name'); + +#### `array_get()` {#collection-method} - // array('Taylor', 'Dayle'); +The `array_get` function retrieves a value from a deeply nested array using "dot" notation: -### array_first + $array = ['products' => ['desk' => ['price' => 100]]]; -`array_first` method သည္ ေပးထားေသာ array အတြင္း မွ ေပးထားေသာ truth test ကုိ ေျပလည္ ေစ မည့္ ပထမဆုံး element အား return ျပန္ေပးပါသည္။ + $value = array_get($array, 'products.desk'); - $array = array(100, 200, 300); + // ['price' => 100] - $value = array_first($array, function($key, $value) - { - return $value >= 150; - }); +The `array_get` function also accepts a default value, which will be returned if the specific key is not found: -default တန္ဖုိးတစ္ခုကုိ လည္း တတိယ parameter အျဖစ္ ထည့္သြင္းေပးနုိင္ပါသည္။ + $value = array_get($array, 'names.john', 'default'); - $value = array_first($array, $callback, $default); + +#### `array_has()` {#collection-method} -### array_last +The `array_has` function checks that a given item or items exists in an array using "dot" notation: -`array_last` method သည္ ေပးထားေသာ array အတြင္းမွ ေပးထားေသာ truth test ကုိ ေျပလည္ေစမည့္ ေနာက္ဆုံး element အား return ျပန္ေပးပါသည္။ + $array = ['product' => ['name' => 'desk', 'price' => 100]]; - $array = array(350, 400, 500, 300, 200, 100); + $hasItem = array_has($array, 'product.name'); - $value = array_last($array, function($key, $value) - { - return $value > 350; - }); + // true - // 500 + $hasItems = array_has($array, ['product.price', 'product.discount']); -default တန္ဖုိးတစ္ခုကုိ လည္း တတိယ parameter အျဖစ္ ထည့္သြင္းေပးနုိင္ပါသည္။ + // false - $value = array_last($array, $callback, $default); + +#### `array_last()` {#collection-method} -### array_flatten +The `array_last` function returns the last element of an array passing a given truth test: -`array_flatten` method သည္ ေပးထားေသာ dimension တစ္ခုထက္ပုိသည့္ array တစ္ခုကို တစ္ဆင့္တည္း ရွိေသာ array တစ္ခု အျဖစ္ return ျပန္ေပးပါသည္။ + $array = [100, 200, 300, 110]; - $array = array('name' => 'Joe', 'languages' => array('PHP', 'Ruby')); + $value = array_last($array, function ($value, $key) { + return $value >= 150; + }); - $array = array_flatten($array); + // 300 - // array('Joe', 'PHP', 'Ruby'); + +#### `array_only()` {#collection-method} -### array_forget +The `array_only` function will return only the specified key / value pairs from the given array: -`array_forget` method သည္ အဆင့္ဆင့္နက္နဲစြာ ညွပ္ထားေသာ deeply nested array တစ္ခုမွ "." သေကၤတသုံးေရးနည္းကုိ အသုံးျပု၍ ေရးထားေသာ ေပးရင္း key နွင့္ တန္ဖုိး အတြဲကုိ ဖယ္ရွားေပးပါသည္။ + $array = ['name' => 'Desk', 'price' => 100, 'orders' => 10]; - $array = array('names' => array('joe' => array('programmer'))); + $array = array_only($array, ['name', 'price']); - array_forget($array, 'names.joe'); + // ['name' => 'Desk', 'price' => 100] -### array_get + +#### `array_pluck()` {#collection-method} -`array_get` method သည္ အဆင့္ဆင့္နက္နဲစြာ ညွပ္ထားေသာ deeply nested array တစ္ခုမွ "." သေကၤတသုံးေရးနည္းကုိ အသုံးျပု၍ ေရးထားေသာ ေပးရင္း key နွင့္ တန္ဖုိး အတြဲကုိ ထုတ္ယူေပးပါသည္။ +The `array_pluck` function will pluck a list of the given key / value pairs from the array: - $array = array('names' => array('joe' => array('programmer'))); + $array = [ + ['developer' => ['id' => 1, 'name' => 'Taylor']], + ['developer' => ['id' => 2, 'name' => 'Abigail']], + ]; - $value = array_get($array, 'names.joe'); + $array = array_pluck($array, 'developer.name'); ->**မွတ္ခ်က္** အကယ္၍ `array_get` ၏ အလုပ္လုပ္ပုံမ် ိုး ကုိ object မ်ားတြင္ သုံးလုိပါက `object_get` အားသုံးနုိင္ပါသည္။ + // ['Taylor', 'Abigail']; -### array_only +You may also specify how you wish the resulting list to be keyed: -`array_only` method သည္ ပထမ argument array အတြင္းမွ ေပးထားေသာ key သုိ့မဟုတ္ တန္ဖုိးမ်ား ပါ၀င္သည့္ အတြဲမ်ားကုိသာ return ျပန္ေပးပါသည္။ + $array = array_pluck($array, 'developer.name', 'developer.id'); - $array = array('name' => 'Joe', 'age' => 27, 'votes' => 1); + // [1 => 'Taylor', 2 => 'Abigail']; - $array = array_only($array, array('name', 'votes')); + +#### `array_prepend()` {#collection-method} -### array_pluck +The `array_prepend` function will push an item onto the beginning of an array: -`array_pluck` method သည္ ပထမ argument array ထံမွ ေပးထားေသာ key သို့ မဟုတ္ တန္ဖုိး ပါ၀င္သည့္ အတြဲကုိသာ return ျပန္ေပးပါသည္။ + $array = ['one', 'two', 'three', 'four']; - $array = array(array('name' => 'Taylor'), array('name' => 'Dayle')); + $array = array_prepend($array, 'zero'); - $array = array_pluck($array, 'name'); + // $array: ['zero', 'one', 'two', 'three', 'four'] - // array('Taylor', 'Dayle'); + +#### `array_pull()` {#collection-method} -### array_pull +The `array_pull` function returns and removes a key / value pair from the array: -`array_pull` method သည္ ပထမ argument array ထံမွ ေပးထားေသာ key သုိ့ မဟုတ္ တန္ဖုိးပါ၀င္သည့္ အတြဲ ကုိ return ျပန္ျပီး ထုိ အတြဲအား မူလ array ထံမွလည္း ဖယ္ရွားေပးပါသည္။ + $array = ['name' => 'Desk', 'price' => 100]; - $array = array('name' => 'Taylor', 'age' => 27); + $name = array_pull($array, 'name'); - $name = array_pull($array, 'name'); + // $name: Desk -### array_set + // $array: ['price' => 100] -`array_set` method သည္ အဆင့္ဆင့္နက္နဲစြာ ညွပ္ထားေသာ array တစ္ခုအတြင္းမွ "." သေကၤတသုံးေရးနည္းကုိ အသုံးျပု၍ ေရးထားေသာ ဒုတိယ argument နွင့္ကုိက္ညီသည့္ တန္ဖုိးအား ျပု ျပင္ထည့္သြင္းေပးပါသည္။ + +#### `array_set()` {#collection-method} - $array = array('names' => array('programmer' => 'Joe')); +The `array_set` function sets a value within a deeply nested array using "dot" notation: - array_set($array, 'names.editor', 'Taylor'); + $array = ['products' => ['desk' => ['price' => 100]]]; -### array_sort + array_set($array, 'products.desk.price', 200); -`array_sort` method သည္ ေပးထားေသာ array အား ေပးထားေသာ Closure function ၏ ရလဒ္ကုိ အသုံးျပု ၍ စီေပးပါသည္။ + // ['products' => ['desk' => ['price' => 200]]] - $array = array( - array('name' => 'Jill'), - array('name' => 'Barry'), - ); + +#### `array_sort()` {#collection-method} - $array = array_values(array_sort($array, function($value) - { - return $value['name']; - })); +The `array_sort` function sorts the array by the results of the given Closure: -### array_where + $array = [ + ['name' => 'Desk'], + ['name' => 'Chair'], + ]; -`array_where` သည္ ေပးထားေသာ array အား ေပးထားေသာ Closure function တစ္ခုျဖင့္ filter လုပ္ေပးပါသည္။ + $array = array_values(array_sort($array, function ($value) { + return $value['name']; + })); - $array = array(100, '200', 300, '400', 500); + /* + [ + ['name' => 'Chair'], + ['name' => 'Desk'], + ] + */ - $array = array_where($array, function($key, $value) - { - return is_string($value); - }); + +#### `array_sort_recursive()` {#collection-method} - // Array ( [1] => 200 [3] => 400 ) +The `array_sort_recursive` function recursively sorts the array using the `sort` function: -### head + $array = [ + [ + 'Roman', + 'Taylor', + 'Li', + ], + [ + 'PHP', + 'Ruby', + 'JavaScript', + ], + ]; -array တစ္ခု၏ ပထမဆုံး element ကုိ return ျပန္ေပးပါသည္။ PHP 5.3.x တြင္ အသုံးျပုနုိင္ေသာ method chaining အတြက္ အသုံး၀င္ပါသည္။ + $array = array_sort_recursive($array); - $first = head($this->returnsArray('foo')); + /* + [ + [ + 'Li', + 'Roman', + 'Taylor', + ], + [ + 'JavaScript', + 'PHP', + 'Ruby', + ] + ]; + */ -### last + +#### `array_where()` {#collection-method} -array တစ္ခု၏ ေနာက္ဆုံး element ကို return ျပန္ေပးပါသည္။ method chaining အတြက္ အသုံး၀င္ပါသည္။ +The `array_where` function filters the array using the given Closure: - $last = last($this->returnsArray('foo')); + $array = [100, '200', 300, '400', 500]; + + $array = array_where($array, function ($value, $key) { + return is_string($value); + }); + + // [1 => 200, 3 => 400] + + +#### `head()` {#collection-method} + +The `head` function simply returns the first element in the given array: + + $array = [100, 200, 300]; + + $first = head($array); + + // 100 + + +#### `last()` {#collection-method} + +The `last` function returns the last element in the given array: + + $array = [100, 200, 300]; + + $last = last($array); + + // 300 ## Paths -### app_path + +#### `app_path()` {#collection-method} + +The `app_path` function returns the fully qualified path to the `app` directory. You may also use the `app_path` function to generate a fully qualified path to a file relative to the application directory: + + $path = app_path(); + + $path = app_path('Http/Controllers/Controller.php'); + + +#### `base_path()` {#collection-method} + +The `base_path` function returns the fully qualified path to the project root. You may also use the `base_path` function to generate a fully qualified path to a given file relative to the project root directory: + + $path = base_path(); + + $path = base_path('vendor/bin'); + + +#### `config_path()` {#collection-method} + +The `config_path` function returns the fully qualified path to the application configuration directory: + + $path = config_path(); -`app` directory၏ path အျပည့္အစုံကုိ ေပးပါသည္။ + +#### `database_path()` {#collection-method} - $path = app_path(); +The `database_path` function returns the fully qualified path to the application's database directory: -### base_path + $path = database_path(); -application ကုိ install လုပ္ထားေသာ root directory ၏ path အျပည့္အစုံကုိ ေပးပါသည္။ + +#### `mix()` {#collection-method} -### public_path +The `mix` function gets the path to a [versioned Mix file](/docs/{{version}}/mix): -`public` directory ၏ path အျပည့္အစုံကုိ ေပးပါသည္။ + mix($file); -### storage_path + +#### `public_path()` {#collection-method} -`app/storage` directory ၏ path အျပည့္အစုံကုိ ေပးပါသည္။ +The `public_path` function returns the fully qualified path to the `public` directory: + + $path = public_path(); + + +#### `resource_path()` {#collection-method} + +The `resource_path` function returns the fully qualified path to the `resources` directory. You may also use the `resource_path` function to generate a fully qualified path to a given file relative to the storage directory: + + $path = resource_path(); + + $path = resource_path('assets/sass/app.scss'); + + +#### `storage_path()` {#collection-method} + +The `storage_path` function returns the fully qualified path to the `storage` directory. You may also use the `storage_path` function to generate a fully qualified path to a given file relative to the storage directory: + + $path = storage_path(); + + $path = storage_path('app/file.txt'); ## Strings -### camel_case + +#### `camel_case()` {#collection-method} -ေပးထားေသာ string အား `camelCase` ေရးဟန္သုိ့ ေျပာင္းလဲေပးပါသည္။ +The `camel_case` function converts the given string to `camelCase`: - $camel = camel_case('foo_bar'); + $camel = camel_case('foo_bar'); - // fooBar + // fooBar -### class_basename + +#### `class_basename()` {#collection-method} -ေပးထားေသာ class ၏ အမည္ကုိ namespace အမည္မ်ား မပါ၀င္ပဲ ေပးပါသည္။ +The `class_basename` returns the class name of the given class with the class' namespace removed: - $class = class_basename('Foo\Bar\Baz'); + $class = class_basename('Foo\Bar\Baz'); - // Baz + // Baz -### e + +#### `e()` {#collection-method} -`htmlentities` function အား ေပးထားေသာ string ျဖင့္ run ပါသည္။ UTF-8 support ပါ၀င္ပါသည္။ +The `e` function runs `htmlspecialchars` over the given string: - $entities = e('foo'); + echo e('foo'); -### ends_with + // <html>foo</html> -ပထမ argument တြင္ ေပးထားေသာ string တစ္ခုသည္ ေပးထားေသာ string နွင့္ အဆုံးသတ္ျခင္းရွိမရွိ ဆုံးျဖတ္ေပးပါသည္။ + +#### `ends_with()` {#collection-method} - $value = ends_with('This is my name', 'name'); +The `ends_with` function determines if the given string ends with the given value: -### snake_case + $value = ends_with('This is my name', 'name'); -ေပးထားေသာ string အား `snake_case` ေရးဟန္ သုိ့ ေျပာင္းလဲေပးပါသည္။ + // true - $snake = snake_case('fooBar'); + +#### `snake_case()` {#collection-method} - // foo_bar +The `snake_case` function converts the given string to `snake_case`: -### str_limit + $snake = snake_case('fooBar'); -string တစ္ခု အတြင္းရွိ အကၡရာအေရအတြက္ကုိ ကန့္သတ္ေပးပါသည္။ + // foo_bar - str_limit($value, $limit = 100, $end = '...') + +#### `str_limit()` {#collection-method} -ဥပမာ +The `str_limit` function limits the number of characters in a string. The function accepts a string as its first argument and the maximum number of resulting characters as its second argument: - $value = str_limit('The PHP framework for web artisans.', 7); + $value = str_limit('The PHP framework for web artisans.', 7); - // The PHP... + // The PHP... -### starts_with + +#### `starts_with()` {#collection-method} -ပထမ argument တြင္ ေပးထားေသာ string တစ္ခုသည္ ေပးထားေသာ string နွင့္ စတင္ျခင္းရွိမရွိ ဆုံးျဖတ္ေပးပါသည္။ +The `starts_with` function determines if the given string begins with the given value: - $value = starts_with('This is my name', 'This'); + $value = starts_with('This is my name', 'This'); -### str_contains + // true -ပထမ argument တြင္ ေပးထားေသာ string တြင္ ေပးထားေသာ string ပါ၀င္ျခင္းရွိမရွိ ဆုံးျဖတ္ေပးပါသည္။ + +#### `str_contains()` {#collection-method} - $value = str_contains('This is my name', 'my'); +The `str_contains` function determines if the given string contains the given value: -### str_finish + $value = str_contains('This is my name', 'my'); -ပထမ argument တြင္ေပးထားေသာ string ၏ အဆုံးတြင္ ေပးထားေသာ string အားေပါင္းထည့္ေပးပါသည္။ + // true - $string = str_finish('this/string', '/'); +You may also pass an array of values to determine if the given string contains any of the values: - // this/string/ + $value = str_contains('This is my name', ['my', 'foo']); -### str_is + // true -ေပးထားေသာ pattern တစ္ခုသည္ ေပးထားေသာ string နွင့္ ကုိက္ညီ မကုိက္ညီ ဆုံးျဖတ္ေပးပါသည္။ ခေရပြင့္အကၡရာ "*" မ်ားအား wildcard အကၡရာအျဖစ္သုံးနုိင္ပါသည္။ + +#### `str_finish()` {#collection-method} - $value = str_is('foo*', 'foobar'); +The `str_finish` function adds a single instance of the given value to a string: -### str_plural + $string = str_finish('this/string', '/'); -ေပးထားေသာ string တစ္ခုအား English ဘာသာ ျဖင့္ အမ်ားကိန္း (plural) ပုံစံသုိ့ ေျပာင္းလဲေပးပါသည္။ + // this/string/ - $plural = str_plural('car'); + +#### `str_is()` {#collection-method} -### str_random +The `str_is` function determines if a given string matches a given pattern. Asterisks may be used to indicate wildcards: -ေပးထားေသာ အေရအတြက္အတုိင္း အတိအက် ရွိသည့္ က်ပန္း string တစ္ခုကုိ ထုတ္ေပးပါသည္။ + $value = str_is('foo*', 'foobar'); - $string = str_random(40); + // true -### str_singular + $value = str_is('baz*', 'foobar'); -ေပးထားေသာ string တစ္ခုအား English ဘာသာ ျဖင့္ အနည္းကိန္း (singular) ပုံစံသုိ့ ေျပာင္းလဲေပးပါသည္။ + // false - $singular = str_singular('cars'); + +#### `str_plural()` {#collection-method} -### studly_case +The `str_plural` function converts a string to its plural form. This function currently only supports the English language: -ေပးထားေသာ string အား `StudlyCase` ေရးဟန္သုိ့ ေျပာင္းလဲေပးပါသည္။ + $plural = str_plural('car'); - $value = studly_case('foo_bar'); + // cars - // FooBar + $plural = str_plural('child'); -### trans + // children -ေပးထားေသာ string တစ္ေျကာင္းအား ဘာသာျပန္ေပးပါသည္။ `Lang::get` method ၏ အမည္ေျပာင္း method တစ္ခုျဖစ္ပါသည္။ +You may provide an integer as a second argument to the function to retrieve the singular or plural form of the string: - $value = trans('validation.required'): + $plural = str_plural('child', 2); -### trans_choice + // children -ေပးထားေသာ string တစ္ေျကာင္းအား ေပးထားေသာ နံပါတ္ အလုိက္ ဘာသာျပန္ message ကုိ အသုံးျပု၍ ဘာသာျပန္ေပးပါသည္။ `Lang::choice` method ၏ အမည္ေျပာင္း method တစ္ခုျဖစ္ပါသည္။ + $plural = str_plural('child', 1); - $value = trans_choice('foo.bar', $count); + // child - -## URLs + +#### `str_random()` {#collection-method} + +The `str_random` function generates a random string of the specified length. This function uses PHP's `random_bytes` function: + + $string = str_random(40); + + +#### `str_singular()` {#collection-method} + +The `str_singular` function converts a string to its singular form. This function currently only supports the English language: + + $singular = str_singular('cars'); + + // car + + +#### `str_slug()` {#collection-method} + +The `str_slug` function generates a URL friendly "slug" from the given string: + + $title = str_slug('Laravel 5 Framework', '-'); + + // laravel-5-framework + + +#### `studly_case()` {#collection-method} -### action +The `studly_case` function converts the given string to `StudlyCase`: -ေပးထားေသာ controller action တစ္စုံအတြက္ URL တစ္ခု ထုတ္ေပးပါသည္။ + $value = studly_case('foo_bar'); - $url = action('HomeController@getIndex', $params); + // FooBar -### route + +#### `title_case()` {#collection-method} -ေပးထားေသာ အမည္ရွိ လမ္းေျကာင္း တစ္ခုအတြက္ URL တစ္ခု ထုတ္ေပးပါသည္။ +The `title_case` function converts the given string to `Title Case`: - $url = route('routeName', $params); + $title = title_case('a nice title uses the correct case'); -### asset + // A Nice Title Uses The Correct Case -ေပးထားေသာ asset အတြက္ URL တစ္ခု ထုတ္ေပးပါသည္။ + +#### `trans()` {#collection-method} - $url = asset('img/photo.jpg'); +The `trans` function translates the given language line using your [localization files](/docs/{{version}}/localization): -### link_to + echo trans('validation.required'): -ေပးထားေသာ URL အတြက္ HTML link တစ္ခု ထုတ္ေပးပါသည္။ + +#### `trans_choice()` {#collection-method} - echo link_to('foo/bar', $title, $attributes = array(), $secure = null); +The `trans_choice` function translates the given language line with inflection: -### link_to_asset + $value = trans_choice('foo.bar', $count); -ေပးထားေသာ asset အတြက္ HTML link တစ္ခု ထုတ္ေပးပါသည္။ + +## URLs + + +#### `action()` {#collection-method} + +The `action` function generates a URL for the given controller action. You do not need to pass the full namespace to the controller. Instead, pass the controller class name relative to the `App\Http\Controllers` namespace: + + $url = action('HomeController@getIndex'); + +If the method accepts route parameters, you may pass them as the second argument to the method: + + $url = action('UserController@profile', ['id' => 1]); + + +#### `asset()` {#collection-method} + +Generate a URL for an asset using the current scheme of the request (HTTP or HTTPS): + + $url = asset('img/photo.jpg'); + + +#### `secure_asset()` {#collection-method} - echo link_to_asset('foo/bar.zip', $title, $attributes = array(), $secure = null); +Generate a URL for an asset using HTTPS: -### link_to_route + echo secure_asset('foo/bar.zip', $title, $attributes = []); -ေပးထားေသာ လမ္းေျကာင္း တစ္ခု အတြက္ HTML link တစ္ခု ထုတ္ေပးပါသည္။ + +#### `route()` {#collection-method} - echo link_to_route('route.name', $title, $parameters = array(), $attributes = array()); +The `route` function generates a URL for the given named route: -### link_to_action + $url = route('routeName'); -ေပးထားေသာ controller action တစ္စုံအတြက္ HTML link တစ္ခု ထုတ္ေပးပါသည္။ +If the route accepts parameters, you may pass them as the second argument to the method: - echo link_to_action('HomeController@getIndex', $title, $parameters = array(), $attributes = array()); + $url = route('routeName', ['id' => 1]); -### secure_asset + +#### `secure_url()` {#collection-method} -ေပးထားေသာ asset အတြက္ HTTPS သုံးထားေသာ HTML link တစ္ခု ထုတ္ေပးပါသည္။ +The `secure_url` function generates a fully qualified HTTPS URL to the given path: - echo secure_asset('foo/bar.zip', $title, $attributes = array()); + echo secure_url('user/profile'); -### secure_url + echo secure_url('user/profile', [1]); -ေပးထားေသာ path တစ္ခု အတြက္ URL အျပည့္အစုံ တစ္ခု ထုတ္ေပးပါသည္။ + +#### `url()` {#collection-method} - echo secure_url('foo/bar', $parameters = array()); +The `url` function generates a fully qualified URL to the given path: -### url + echo url('user/profile'); -ေပးထားေသာ path တစ္ခု အတြက္ URL အျပည့္အစုံ ထုတ္ေပးပါသည္။ + echo url('user/profile', [1]); - echo url('foo/bar', $parameters = array(), $secure = null); +If no path is provided, a `Illuminate\Routing\UrlGenerator` instance is returned: + + echo url()->current(); + echo url()->full(); + echo url()->previous(); ## Miscellaneous -### csrf_token + +#### `abort()` {#collection-method} + +The `abort` function throws a HTTP exception which will be rendered by the exception handler: + + abort(401); + +You may also provide the exception's response text: + + abort(401, 'Unauthorized.'); + + +#### `abort_if()` {#collection-method} + +The `abort_if` function throws an HTTP exception if a given boolean expression evaluates to `true`: + + abort_if(! Auth::user()->isAdmin(), 403); + + +#### `abort_unless()` {#collection-method} + +The `abort_unless` function throws an HTTP exception if a given boolean expression evaluates to `false`: + + abort_unless(Auth::user()->isAdmin(), 403); + + +#### `auth()` {#collection-method} + +The `auth` function returns an authenticator instance. You may use it instead of the `Auth` facade for convenience: + + $user = auth()->user(); + + +#### `back()` {#collection-method} + +The `back()` function generates a redirect response to the user's previous location: + + return back(); + + +#### `bcrypt()` {#collection-method} + +The `bcrypt` function hashes the given value using Bcrypt. You may use it as an alternative to the `Hash` facade: + + $password = bcrypt('my-secret-password'); + + +#### `cache()` {#collection-method} + +The `cache` function may be used to get values from the cache. If the given key does not exist in the cache, an optional default value will be returned: + + $value = cache('key'); + + $value = cache('key', 'default'); + +You may add items to the cache by passing an array of key / value pairs to the function. You should also pass the number of minutes or duration the cached value should be considered valid: + + cache(['key' => 'value'], 5); + + cache(['key' => 'value'], Carbon::now()->addSeconds(10)); + + +#### `collect()` {#collection-method} + +The `collect` function creates a [collection](/docs/{{version}}/collections) instance from the given array: + + $collection = collect(['taylor', 'abigail']); + + +#### `config()` {#collection-method} + +The `config` function gets the value of a configuration variable. The configuration values may be accessed using "dot" syntax, which includes the name of the file and the option you wish to access. A default value may be specified and is returned if the configuration option does not exist: + + $value = config('app.timezone'); + + $value = config('app.timezone', $default); + +The `config` helper may also be used to set configuration variables at runtime by passing an array of key / value pairs: + + config(['app.debug' => true]); + + +#### `csrf_field()` {#collection-method} + +The `csrf_field` function generates an HTML `hidden` input field containing the value of the CSRF token. For example, using [Blade syntax](/docs/{{version}}/blade): + + {{ csrf_field() }} + + +#### `csrf_token()` {#collection-method} + +The `csrf_token` function retrieves the value of the current CSRF token: + + $token = csrf_token(); + + +#### `dd()` {#collection-method} + +The `dd` function dumps the given variables and ends execution of the script: + + dd($value); + + dd($value1, $value2, $value3, ...); + +If you do not want to halt the execution of your script, use the `dump` function instead: + + dump($value); + + +#### `dispatch()` {#collection-method} + +The `dispatch` function pushes a new job onto the Laravel [job queue](/docs/{{version}}/queues): + + dispatch(new App\Jobs\SendEmails); + + +#### `env()` {#collection-method} + +The `env` function gets the value of an environment variable or returns a default value: + + $env = env('APP_ENV'); + + // Return a default value if the variable doesn't exist... + $env = env('APP_ENV', 'production'); + + +#### `event()` {#collection-method} + +The `event` function dispatches the given [event](/docs/{{version}}/events) to its listeners: + + event(new UserRegistered($user)); + + +#### `factory()` {#collection-method} + +The `factory` function creates a model factory builder for a given class, name, and amount. It can be used while [testing](/docs/{{version}}/database-testing#writing-factories) or [seeding](/docs/{{version}}/seeding#using-model-factories): + + $user = factory(App\User::class)->make(); + + +#### `info()` {#collection-method} + +The `info` function will write information to the log: + + info('Some helpful information!'); + +An array of contextual data may also be passed to the function: + + info('User login attempt failed.', ['id' => $user->id]); + + +#### `logger()` {#collection-method} + +The `logger` function can be used to write a `debug` level message to the log: + + logger('Debug message'); + +An array of contextual data may also be passed to the function: + + logger('User has logged in.', ['id' => $user->id]); + +A [logger](/docs/{{version}}/errors#logging) instance will be returned if no value is passed to the function: + + logger()->error('You are not allowed here.'); + + +#### `method_field()` {#collection-method} + +The `method_field` function generates an HTML `hidden` input field containing the spoofed value of the form's HTTP verb. For example, using [Blade syntax](/docs/{{version}}/blade): + +
    + {{ method_field('DELETE') }} +
    + + +#### `old()` {#collection-method} + +The `old` function [retrieves](/docs/{{version}}/requests#retrieving-input) an old input value flashed into the session: + + $value = old('value'); + + $value = old('value', 'default'); + + +#### `redirect()` {#collection-method} + +The `redirect` function returns a redirect HTTP response, or returns the redirector instance if called with no arguments: + + return redirect('/home'); + + return redirect()->route('route.name'); + + +#### `request()` {#collection-method} + +The `request` function returns the current [request](/docs/{{version}}/requests) instance or obtains an input item: + + $request = request(); + + $value = request('key', $default = null) + + +#### `response()` {#collection-method} + +The `response` function creates a [response](/docs/{{version}}/responses) instance or obtains an instance of the response factory: + + return response('Hello World', 200, $headers); + + return response()->json(['foo' => 'bar'], 200, $headers); + + +#### `retry()` {#collection-method} + +The `retry` function attempts to execute the given callback until the given maximum attempt threshold is met. If the callback does not throw an exception, it's return value will be returned. If the callback throws an exception, it will automatically be retried. If the maximum attempt count is exceeded, the exception will be thrown: + + return retry(5, function () { + // Attempt 5 times while resting 100ms in between attempts... + }, 100); + + +#### `session()` {#collection-method} + +The `session` function may be used to get or set session values: + + $value = session('key'); -လက္ရွိ CSRF token တန္ဖုိးကုိ ေပးပါသည္။ +You may set values by passing an array of key / value pairs to the function: - $token = csrf_token(); + session(['chairs' => 7, 'instruments' => 3]); -### dd +The session store will be returned if no value is passed to the function: -ေပးထားေသာ variable ကုိ dump လုပ္၍ script execution ကုိ ရပ္ေစပါသည္။ + $value = session()->get('key'); - dd($value); + session()->put('key', $value); -### value + +#### `value()` {#collection-method} -ေပးထားေသာ တန္ဖုိးသည္ `Closure` တစ္ခု ျဖစ္ပါက `Closure` မွတစ္ဆင့္ return ျပန္လာေသာ value ကုိ return ျပန္ေပး၍ `Closure` မဟုတ္ပါက တန္ဖုိးအတုိင္း return ျပန္ေပးပါသည္။ +The `value` function's behavior will simply return the value it is given. However, if you pass a `Closure` to the function, the `Closure` will be executed then its result will be returned: - $value = value(function() { return 'bar'; }); + $value = value(function () { + return 'bar'; + }); -### with + +#### `view()` {#collection-method} -ေပးထားေသာ object ကုိ return ျပန္ေပးပါသည္။ PHP 5.3.x တြင္ method chaining constructor မ်ား အတြက္ အသုံး၀င္ပါသည္။ +The `view` function retrieves a [view](/docs/{{version}}/views) instance: - $value = with(new Foo)->doWork(); \ No newline at end of file + return view('auth.login'); diff --git a/homestead.md b/homestead.md index 7858c48..35874b1 100644 --- a/homestead.md +++ b/homestead.md @@ -1,128 +1,339 @@ -# Laravel ရဲ့ Official Development Homestead အကြောင်း +# Laravel Homestead -- [Homestead မိတ်ဆက်](#introduction) -- [Homestead မှာပါဝင်သော Software များ](#included-software) +- [Introduction](#introduction) - [Installation & Setup](#installation-and-setup) -- [နေ့စဉ်အသုံးပြုမှူ](#general-usage) -- [Ports](#ports) + - [First Steps](#first-steps) + - [Configuring Homestead](#configuring-homestead) + - [Launching The Vagrant Box](#launching-the-vagrant-box) + - [Per Project Installation](#per-project-installation) + - [Installing MariaDB](#installing-mariadb) +- [Daily Usage](#daily-usage) + - [Accessing Homestead Globally](#accessing-homestead-globally) + - [Connecting Via SSH](#connecting-via-ssh) + - [Connecting To Databases](#connecting-to-databases) + - [Adding Additional Sites](#adding-additional-sites) + - [Configuring Cron Schedules](#configuring-cron-schedules) + - [Ports](#ports) +- [Network Interfaces](#network-interfaces) +- [Updating Homestead](#updating-homestead) +- [Old Versions](#old-versions) -## Homestead မိတ်ဆက် +## Introduction -သင့်ရဲ့ PHP Development environment ကို local development environment မှာပါ ကြည်နူးသာယာဖွယ်ကောင်းအောင်Laravel က အကောင်းဆုံးကြိုးစားအားထုတ်မှူတစ်ခုလုပ်ခဲ့ပါတယ်။ [Vagrant](http://vagrantup.com) ကသင့်ရဲ့ Virtual Machine တွေကို လွယ်လွယ်ကူကူ ထိန်းသိမ်း နိုင်အောင် သင့်ကိုထောက်ပံ့ ပေးထားပါတယ်။ +Laravel strives to make the entire PHP development experience delightful, including your local development environment. [Vagrant](https://www.vagrantup.com) provides a simple, elegant way to manage and provision Virtual Machines. +Laravel Homestead is an official, pre-packaged Vagrant box that provides you a wonderful development environment without requiring you to install PHP, a web server, and any other server software on your local machine. No more worrying about messing up your operating system! Vagrant boxes are completely disposable. If something goes wrong, you can destroy and re-create the box in minutes! -Laravel Homestead က official ပါ၊ Vagrant "box" မှာ ကြိုု ပြီး package လုပ်ထားတာပါ... နောက် အဲဒါကသင့်ကို development environment တစ်ခု တည်ဆောက်တဲ့နေရာမှာ PHP, a web server, နဲ့ အခြားအသုံးဝင်တဲ့ tools တွေကို သင့်ရဲ့ local machine မှာ install လုပ်စရာမလိုပါဘူး။ ဘယ် Opearting System ကိုသုံးတယ်ဆိုတာကိုလည်း worry များစရာမလိုတော့ပါဘူး။ Vagrant boxes တွေနဲ့ဘဲ အသုံးပြုလို့ရပါတယ်။ တကယ်လို့တစ်ခုခုမှားသွားတယ်ဆိုရင် vagrant boxes တွေကိုမိနစ်အနည်းငယ်အတွင်း destory လုပ်ပြီးတော့ ပြန်ပြီး create လုပ်နိုင်ပါတယ်။ +Homestead runs on any Windows, Mac, or Linux system, and includes the Nginx web server, PHP 7.1, MySQL, Postgres, Redis, Memcached, Node, and all of the other goodies you need to develop amazing Laravel applications. -Homestead က မည်သည့် Window, Mac, Linux မှာမဆို run ပါတယ်။ Homesead မှာ Nginx web server, PHP 5.5, MySQL, Postgres, Redis, Memcached နဲ့ အခြား Laravel application အတွက် အသုံးဝင်တာတွေပါဝင်ပါတယ်။ +> {note} If you are using Windows, you may need to enable hardware virtualization (VT-x). It can usually be enabled via your BIOS. If you are using Hyper-V on a UEFI system you may additionally need to disable Hyper-V in order to access VT-x. -## Homestead မှာပါဝင်သော Software များ +### Included Software -- Ubuntu 14.04 -- PHP 5.5 +- Ubuntu 16.04 +- Git +- PHP 7.1 - Nginx - MySQL +- MariaDB +- Sqlite3 - Postgres -- Node (With Bower, Grunt, and Gulp) +- Composer +- Node (With Yarn, PM2, Bower, Grunt, and Gulp) - Redis - Memcached - Beanstalkd -- [Laravel Envoy](ssh#envoy-task-runner.md) -- Fabric + HipChat Extension ## Installation & Setup -### VirtualBox နဲ့ Vagrant Installing + +### First Steps -သင်အနေနဲ့ Homestead environment ကိုမဖွင့်ခင် [VirtualBox](https://www.virtualbox.org/wiki/Downloads) နဲ့ [Vagrant](http://www.vagrantup.com/downloads.html) ကို install လုပ်ထားရပါ့မယ်။ ဒီ software နှစ်ခုပေါင်းပြီး popular operating systems များကိုလွယ်ကူစွာ virtual install လုပ်လို့ရပါမည်။ +Before launching your Homestead environment, you must install [VirtualBox 5.1](https://www.virtualbox.org/wiki/Downloads), [VMWare](https://www.vmware.com), or [Parallels](http://www.parallels.com/products/desktop/) as well as [Vagrant](https://www.vagrantup.com/downloads.html). All of these software packages provide easy-to-use visual installers for all popular operating systems. -### Vagrant Box များထည့်ခြင်း +To use the VMware provider, you will need to purchase both VMware Fusion / Workstation and the [VMware Vagrant plug-in](https://www.vagrantup.com/vmware). Though it is not free, VMware can provide faster shared folder performance out of the box. -VirtualBox နဲ့ Vagrant ကို install လုပ်ပြီးပြီဆိုရင် ပထမဆုံး သင့်ရဲ့ Vagrant installation မှာ `laravel/homestead` လို့ terminal ကနေ run ပြီး Laravel ရဲ့ Homestead ကို Virtual Box မှာ add လိုက်ပါ။ Laravel ရဲ့ Homestead box ကို download လုပ်ဖို့အတွက် သင့်အင်တာနက် conn ပေါ်မူတည်ပြီး အချိကြာပါ့မယ် +To use the Parallels provider, you will need to install [Parallels Vagrant plug-in](https://github.com/Parallels/vagrant-parallels). It is free of charge. - vagrant box add laravel/homestead +#### Installing The Homestead Vagrant Box -### Clone The Homestead Repository +Once VirtualBox / VMware and Vagrant have been installed, you should add the `laravel/homestead` box to your Vagrant installation using the following command in your terminal. It will take a few minutes to download the box, depending on your Internet connection speed: -သင်ရဲ့ Vagrant Installation မှာ box ထည့်ပြီးသွားပြီဆိုရင် သင့်အနေနဲ့ဒီ repository ကို download ဒါမှမဟုတ် clone လုပ်ပေးပါ။ နားလည်ထားရမှာက ဒီ repositiry က `Homestead` ပါ၊ ဒီ Folder ထဲမှာ သင့်ရဲ့ Laravel Projects တွေကို ထားရမှာပါ၊ Homestead box တွေကသင့်ရဲ့ Laravel (နဲ့ PHP Projects) တွေကို host အဖြစ် run မှာဖြစ်ပါတယ်။ + vagrant box add laravel/homestead - git clone https://github.com/laravel/homestead.git Homestead +If this command fails, make sure your Vagrant installation is up to date. -### Set Your SSH Key +#### Installing Homestead -ပြီးရင်တော့သင် download လုပ်ထားတဲ့ repository ထဲမှာပါတဲ့ `Homestead.yaml` file ကို edit လုပ်သင့်ပါတယ်။ ဒီ file ထဲမှာဆိုရင် သင်ရဲ့ public SSH key တို့ နောက် သင့်ရဲ့ main machine နဲ့ Homestead virtual machine တို့ကို share တဲ့ Folder တို့ကို configure လုပ်နိုင်ပါတယ်။ +You may install Homestead by simply cloning the repository. Consider cloning the repository into a `Homestead` folder within your "home" directory, as the Homestead box will serve as the host to all of your Laravel projects: -သင့်မှာ SSH key မရှိဘူးလား၊ သင်က Linux ဒါမှမဟုတ် Mac မှာဆိုရင် အောက်မှာဖော်ပြထားတဲ့ command ကို run လိုက်တာနဲ့ ssh key တစ်စုံကိုသင့်အတွက်ဖန်တီးပေးပါလိမ့်မယ် + cd ~ - ssh-keygen -t rsa -C "your@email.com" + git clone https://github.com/laravel/homestead.git Homestead -Windows မှာဆိုရင် သင်အနေနဲ့ [Git](http://git-scm.com/) ကို install လုပ်ပြီးတော့ `Git Bash`မှာ အထက်က command ကို run ပြီးတော့ အဆင်ပြေပါတယ်။ အဲလိုမှမဟုတ်ဘူးဆိုရင်လည်း[PuTTY](http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html) and [PuTTYgen](http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html). တို့ကိုအသုံးပြုနိုင်ပါတယ်။ +Once you have cloned the Homestead repository, run the `bash init.sh` command from the Homestead directory to create the `Homestead.yaml` configuration file. The `Homestead.yaml` file will be placed in the `~/.homestead` hidden directory: -သင် SSH Key ကို create လုပ်ပြီးပြီဆိုရင် `Homestead.yaml` file ထဲက `authorize` ဆိုတဲ့ လမ်းကြောင်းထဲမှာ သင့်ရဲ့ SSH Key ရဲ့ path ကိုသတ်မှတ်လိုက်ပါ။ + // Mac / Linux... + bash init.sh -### Configure Your Shared Folders + // Windows... + init.bat -သင့်ရဲ့ Homestead environment နဲ့ သင့်ရဲ့ local machine နှစ်ခုကြားမှာ Share တဲ့ Folder တွေအားလုံးက `Homestead.yaml` File ထဲမှာရှိမှာပါ။ တကယ်လို့ အဲ့ဒီ့ Files တွေ change သွားရင် သင့်ရဲ့ local machine နဲ့ Homestead environment ကို auto sync လုပ်ပေးသွားမှာပါ။ Share Folders တွေအများကြီးကိုလည်းသင်လိုအပ်ရင် configure လုပ်ရမှာပါ။ + +### Configuring Homestead -### Configure Your Nginx Sites +#### Setting Your Provider -Nginx နဲ့သိပ်မရင်းနှီးဘူးမဟုတ်လား ပြသနာမရှိပါဘူး။ `sites` တွေကသင့်ရဲ့ Homestead environment က Folders တွေကို "domain" ဆီကိုလွယ်ကူစွာ map ပေးပါလိမ့်မယ်။ Site configuration တစ်ခုကို `Homestead.yaml` မှာတွေ့နိုင်ပါတယ်။ သင့်အနေနဲ့ sites အများကြီးကိုသင့်ရဲ့ Homestead မှာထည့်ချင်ပါလိမ့်မယ်၊ Homestad က သင့်virtualized Laravel Projects တွေရဲ့ environment တွေကို အဆင်ပြေစေပါလိမ့်မယ်။ +The `provider` key in your `~/.homestead/Homestead.yaml` file indicates which Vagrant provider should be used: `virtualbox`, `vmware_fusion`, `vmware_workstation`, or `parallels`. You may set this to the provider you prefer: -### Bash Aliases + provider: virtualbox -To add Bash aliases to your Homestead box, simply add to the `aliases` file in the root of the Homestead directory. +#### Configuring Shared Folders -### VagrantBox ကိုစတင်ခြင်း +The `folders` property of the `Homestead.yaml` file lists all of the folders you wish to share with your Homestead environment. As files within these folders are changed, they will be kept in sync between your local machine and the Homestead environment. You may configure as many shared folders as necessary: -`Homestead.yaml` file မှာသင့်ရဲ့ link တွေကို edit လုပ်ပြီးပြီဆိုရင် သင့်ရဲ့ `Homestead` directory ထဲမှာ `vagrant up` ဆိုပြီး terminal ကနေ run လိုက်ပါ။ Vagrant က Virtual Machine ကို boot လုပ်ပါ့လိမ့်မယ် ပြီးရင်တော့ သင့်ရဲ့ share folders နဲ့ Nginx sites တွေကို auto configure လုပ်သွားပါလိမ့်မယ်။ + folders: + - map: ~/Code + to: /home/vagrant/Code -သင့်ရဲ့ Nginx sites တွေအတွက် "domain" တွေကို သင်ရဲ့ local machine က hosts မှာထက်ပေါင်းထည့်ဖို့မမေ့ပါနဲ့ဦး။ hosts file ကသင့် local machine က requests တွေကို Homestead ဆီကို redirect လုပ်ပေးပါလိမ့်မယ်။ Mac နဲ့ linux မှာ ဆိုရင် hosts file က `/etc/hosts` ထဲမှာပြင်လို့ရပါတယ်။ Window မှာဆိုရင်တော့ `C:\Windows\System32\drivers\etc\hosts` မှာရှိပါတယ်။ သင်ထက်ပေါင်းထည့်ရမယ့် line က အောက်ကလိုဖြစ်ပါလိမ့်မယ်၊ +To enable [NFS](https://www.vagrantup.com/docs/synced-folders/nfs.html), just add a simple flag to your synced folder configuration: - 127.0.0.1 homestead.app + folders: + - map: ~/Code + to: /home/vagrant/Code + type: "nfs" -သင့်ရဲ့ domain ကိုသင့်ရဲ့ `hosts` file ထဲကိုပေါင်းထည့်ပြီးပြီဆိုရင် သင်ရဲ့ browser ကနေသင့် domain နောက်က port နံပါတ်နဲ့ဆိုရင်သင့်ရဲ့ဆိုက်ကို access လုပ်လို့ရပါပြီ။ +You may also pass any options supported by Vagrant's [Synced Folders](https://www.vagrantup.com/docs/synced-folders/basic_usage.html) by listing them under the `options` key: - http://homestead.app:8000 + folders: + - map: ~/Code + to: /home/vagrant/Code + type: "rsync" + options: + rsync__args: ["--verbose", "--archive", "--delete", "-zz"] + rsync__exclude: ["node_modules"] -သင်ရဲ့ database တွေကိုဘယ်လို connect လုပ်မလဲဆိုတာကို လေ့လာဖို့ ဆက်ဖတ်ပါဦ။ + +#### Configuring Nginx Sites + +Not familiar with Nginx? No problem. The `sites` property allows you to easily map a "domain" to a folder on your Homestead environment. A sample site configuration is included in the `Homestead.yaml` file. Again, you may add as many sites to your Homestead environment as necessary. Homestead can serve as a convenient, virtualized environment for every Laravel project you are working on: + + sites: + - map: homestead.app + to: /home/vagrant/Code/Laravel/public + +If you change the `sites` property after provisioning the Homestead box, you should re-run `vagrant reload --provision` to update the Nginx configuration on the virtual machine. + +#### The Hosts File + +You must add the "domains" for your Nginx sites to the `hosts` file on your machine. The `hosts` file will redirect requests for your Homestead sites into your Homestead machine. On Mac and Linux, this file is located at `/etc/hosts`. On Windows, it is located at `C:\Windows\System32\drivers\etc\hosts`. The lines you add to this file will look like the following: + + 192.168.10.10 homestead.app + +Make sure the IP address listed is the one set in your `~/.homestead/Homestead.yaml` file. Once you have added the domain to your `hosts` file and launched the Vagrant box you will be able to access the site via your web browser: + + http://homestead.app + + +### Launching The Vagrant Box + +Once you have edited the `Homestead.yaml` to your liking, run the `vagrant up` command from your Homestead directory. Vagrant will boot the virtual machine and automatically configure your shared folders and Nginx sites. + +To destroy the machine, you may use the `vagrant destroy --force` command. + + +### Per Project Installation + +Instead of installing Homestead globally and sharing the same Homestead box across all of your projects, you may instead configure a Homestead instance for each project you manage. Installing Homestead per project may be beneficial if you wish to ship a `Vagrantfile` with your project, allowing others working on the project to simply `vagrant up`. + +To install Homestead directly into your project, require it using Composer: + + composer require laravel/homestead --dev + +Once Homestead has been installed, use the `make` command to generate the `Vagrantfile` and `Homestead.yaml` file in your project root. The `make` command will automatically configure the `sites` and `folders` directives in the `Homestead.yaml` file. + +Mac / Linux: + + php vendor/bin/homestead make + +Windows: + + vendor\\bin\\homestead make + +Next, run the `vagrant up` command in your terminal and access your project at `http://homestead.app` in your browser. Remember, you will still need to add an `/etc/hosts` file entry for `homestead.app` or the domain of your choice. + + +### Installing MariaDB + +If you prefer to use MariaDB instead of MySQL, you may add the `mariadb` option to your `Homestead.yaml` file. This option will remove MySQL and install MariaDB. MariaDB serves as a drop-in replacement for MySQL so you should still use the `mysql` database driver in your application's database configuration: + + box: laravel/homestead + ip: "192.168.20.20" + memory: 2048 + cpus: 4 + provider: virtualbox + mariadb: true -## နေ့စဉ်အသုံးပြုမှူ +## Daily Usage + + +### Accessing Homestead Globally + +Sometimes you may want to `vagrant up` your Homestead machine from anywhere on your filesystem. You can do this on Mac / Linux systems by adding a Bash function to your Bash profile. On Windows, you may accomplish this by adding a "batch" file to your `PATH`. This scripts will allow you to run any Vagrant command from anywhere on your system and will automatically point that command to your Homestead installation: + +#### Linux + + function homestead() { + ( cd ~/Homestead && vagrant $* ) + } + +Make sure to tweak the `~/Homestead` path in the function to the location of your actual Homestead installation. Once the function is installed, you may run commands like `homestead up` or `homestead ssh` from anywhere on your system. + +#### Windows + +Create a `homestead.bat` batch file anywhere on your machine with the following contents: + + @echo off -### SSH ကို connect လုပ်ခြင်း + set cwd=%cd% + set homesteadVagrant=C:\Homestead -သင့်ရဲ့ Homestead environment ကို SSH ကနေ ချိတ်ဆက်ဝင်ဖို့ သင့်အနေနဲ့ `127.0.0.1` port ကတော့ 2222 ဖြစ်ပြီး SSH key ကတော့ သင်ရဲ့`Homestead.yaml`မှာ သင်သတ်မှတ်ခဲ့တဲ့ key ဘဲဖြစ်ပါတယ်။ `vagrant ssh` ဆိုပြီးသင့်ရဲ့ Homestead Folder ကနေလည်း ဝင်လို့ရပါတယ်။ + cd /d %homesteadVagrant% && vagrant %* + cd /d %cwd% -သင်အနေနဲ့ ဒါ့ထက်အဆင်ပြေမှူ လိုချင်သေးတယ်ဆိုရင်တော့ အောက်မှာဖော်ပြထားတဲ့ alias ကို သင့်ရဲ့ `~/.bash_aliases` ဒါမှမဟုတ် `~/.bash_profile` မှာပေါင်းထည့်လိုက်တာက ပိုပြီးအသုံးဝင်ပါမယ်၊ + set cwd= + set homesteadVagrant= - alias vm='ssh vagrant@127.0.0.1 -p 2222' +Make sure to tweak the example `C:\Homestead` path in the script to the actual location of your Homestead installation. After creating the file, add the file location to your `PATH`. You may then run commands like `homestead up` or `homestead ssh` from anywhere on your system. -### သင့်ရဲ့ Databases များကို connect လုပ်ခြင်း + +### Connecting Via SSH -homestead` ရဲ့ databases တွေဖြစ်တဲ့ MySQL နဲ့ Postgres နှစ်ခုလုံးကို box တွေရဲ့အပြင်မှာ configuration လုပ်ထားပါတယ်။ ဒါထက်ပိုပြီးအဆင်ပြေဖို့ Laravel ရဲ့ `local` database ကို default configure လုပ်ထားပါတယ်။ +You can SSH into your virtual machine by issuing the `vagrant ssh` terminal command from your Homestead directory. -သင့်ရဲ့ database MySQL ဒါမှမဟုတ် Postgres ကို Navicat (သို့) Sequel Pro ကနေသင့်ရဲ့ main machine နဲ့ connect လုပ်ချင်တယ်ဆိုရင် သင့်အနေနဲ့ MySQL အတွက် `127.0.0.1` နဲ့ port 33060 နဲ့Postgres အတွက် port 54320 ဖြစ်ပါတယ်။ Database နှစ်ခုလုံးအတွက် username နဲ့ password က `homestead`/ `secreat` ဖြစ်ပါတယ်။ +But, since you will probably need to SSH into your Homestead machine frequently, consider adding the "function" described above to your host machine to quickly SSH into the Homestead box. -> **Note:** You should only use these non-standard ports when connecting to the databases from your main machine. You will use the default 3306 and 5432 ports in your Laravel database configuration file since Laravel is running _within_ the Virtual Machine. + +### Connecting To Databases -### နောက်ထက်ဆိုက်တစ်ခု ထပ်ထည့်ခြင်း +A `homestead` database is configured for both MySQL and Postgres out of the box. For even more convenience, Laravel's `.env` file configures the framework to use this database out of the box. -သင့်ရဲ့ Homestead environment ကသင်ထည့်ချင်တာတွေထည့်ပြီးသွားပြီ run လည်း run နေပြီဆိုရင် သင့်အနေနဲ့ Laravel applications တွေကို သင့်ရဲ့ Nginx sites မှာထပ်ထည့်ချင်မှာပေါ့။ Homestead environment တစ်ခုမှာ သင်ကြိုက်သလောက် Laravel installation လုပ်နိုင်ပါတယ်။ Laravel application ထက်ပေါင်းထည့် တဲ့နေရာမှာ နည်းနှစ်ခုရှိပါတယ်။ ပထမတစ်ခုကသင့်ရဲ့ `Homestead.yaml` files မှာထက်ပေါင်းထည့်ပါ ပြီးရင် `vagrant destory` နဲ့ box တွေကို ဖျက်ပါ၊ ပြီးရင် `vagrant up` ပြန်လုပ်ပါ။ +To connect to your MySQL or Postgres database from your host machine's database client, you should connect to `127.0.0.1` and port `33060` (MySQL) or `54320` (Postgres). The username and password for both databases is `homestead` / `secret`. -နောက်ထက်နည်းတစ်ခုကတော့ သင့်ရဲ့ Homestead environment မှာ `serve` script ကိုသုံးပြီး Laravel application တွေကိုထက်ထည့်နိုင်ပါတယ်။ `serve` script ကိုအသုံးပြုချင်တယ်ဆိုရင်တော့ သင့်ရဲ့ Homestead environment ထဲကိုဝင်ပြီးတော့ အောက်က command ကို run လိုက်ပါ +> {note} You should only use these non-standard ports when connecting to the databases from your host machine. You will use the default 3306 and 5432 ports in your Laravel database configuration file since Laravel is running _within_ the virtual machine. - serve domain.app /home/vagrant/Code/path/to/public/directory + +### Adding Additional Sites -> **မှတ်ချက်:** `serve` command ကို run ပြီးပြီဆိုရင် `hosts` file ထဲမှာ သင်ထပ်ပေါင်းထည့်လိုက်တဲ့ နောက်ထက် site ကို သင့်ရဲ့ စက်မှာ ထက်ပေါင်းထည့်ဖို့ မမေ့ပါနဲ့။ +Once your Homestead environment is provisioned and running, you may want to add additional Nginx sites for your Laravel applications. You can run as many Laravel installations as you wish on a single Homestead environment. To add an additional site, simply add the site to your `~/.homestead/Homestead.yaml` file: + + sites: + - map: homestead.app + to: /home/vagrant/Code/Laravel/public + - map: another.app + to: /home/vagrant/Code/another/public + +If Vagrant is not automatically managing your "hosts" file, you may need to add the new site to that file as well: + + 192.168.10.10 homestead.app + 192.168.10.10 another.app + +Once the site has been added, run the `vagrant reload --provision` command from your Homestead directory. + + +### Configuring Cron Schedules + +Laravel provides a convenient way to [schedule Cron jobs](/docs/{{version}}/scheduling) by scheduling a single `schedule:run` Artisan command to be run every minute. The `schedule:run` command will examine the job schedule defined in your `App\Console\Kernel` class to determine which jobs should be run. + +If you would like the `schedule:run` command to be run for a Homestead site, you may set the `schedule` option to `true` when defining the site: + + sites: + - map: homestead.app + to: /home/vagrant/Code/Laravel/public + schedule: true + +The Cron job for the site will be defined in the `/etc/cron.d` folder of the virtual machine. -## Ports +### Ports + +By default, the following ports are forwarded to your Homestead environment: + +- **SSH:** 2222 → Forwards To 22 +- **HTTP:** 8000 → Forwards To 80 +- **HTTPS:** 44300 → Forwards To 443 +- **MySQL:** 33060 → Forwards To 3306 +- **Postgres:** 54320 → Forwards To 5432 + +#### Forwarding Additional Ports + +If you wish, you may forward additional ports to the Vagrant box, as well as specify their protocol: + + ports: + - send: 93000 + to: 9300 + - send: 7777 + to: 777 + protocol: udp + + +## Network Interfaces + +The `networks` property of the `Homestead.yaml` configures network interfaces for your Homestead environment. You may configure as many interfaces as necessary: + + networks: + - type: "private_network" + ip: "192.168.10.20" + +To enable a [bridged](https://www.vagrantup.com/docs/networking/public_network.html) interface, configure a `bridge` setting and change the network type to `public_network`: + + networks: + - type: "public_network" + ip: "192.168.10.20" + bridge: "en1: Wi-Fi (AirPort)" + +To enable [DHCP](https://www.vagrantup.com/docs/networking/public_network.html), just remove the `ip` option from your configuration: + + networks: + - type: "public_network" + bridge: "en1: Wi-Fi (AirPort)" + + +## Updating Homestead + +You can update Homestead in two simple steps. First, you should update the Vagrant box using the `vagrant box update` command: + + vagrant box update + +Next, you need to update the Homestead source code. If you cloned the repository you can simply `git pull origin master` at the location you originally cloned the repository. + +If you have installed Homestead via your project's `composer.json` file, you should ensure your `composer.json` file contains `"laravel/homestead": "^4"` and update your dependencies: + + composer update + + +## Old Versions + +You can easily override the version of the box that Homestead uses by adding the following line to your `Homestead.yaml` file: + + version: 0.6.0 + +An example: + + box: laravel/homestead + version: 0.6.0 + ip: "192.168.20.20" + memory: 2048 + cpus: 4 + provider: virtualbox -အောက်မှာဖော်ပြထားတဲ့ ports တွေက သင့် Homestead ရဲ့ ports တွေဖြစ်ပါတယ် +When you use an older version of the Homestead box you need to match that with a compatible version of the Homestead source code. Below is a chart which shows the supported box versions, which version of Homestead source code to use, and the version of PHP provided: -- **SSH:** 2222 -> Forwards To 22 -- **HTTP:** 8000 -> Forwards To 80 -- **MySQL:** 33060 -> Forwards To 3306 -- **Postgres:** 54320 -> Forwards To 5432 +| | Homestead Version | Box Version | +|---|---|---| +| PHP 7.0 | 3.1.0 | 0.6.0 | +| PHP 7.1 | 4.0.0 | 1.0.0 | diff --git a/html.md b/html.md deleted file mode 100644 index c125e0d..0000000 --- a/html.md +++ /dev/null @@ -1,197 +0,0 @@ -# Forms & HTML - -- [Opening A Form](#opening-a-form) -- [CSRF Protection](#csrf-protection) -- [Form Model Binding](#form-model-binding) -- [Labels](#labels) -- [Text, Text Area, Password & Hidden Fields](#text) -- [Checkboxes and Radio Buttons](#checkboxes-and-radio-buttons) -- [File Input](#file-input) -- [Drop-Down Lists](#drop-down-lists) -- [Buttons](#buttons) -- [Custom Macros](#custom-macros) -- [Generating URLs](#generating-urls) - - -## Opening A Form - -#### Opening A Form - - {{ Form::open(array('url' => 'foo/bar')) }} - // - {{ Form::close() }} - -By default, a `POST` method will be assumed; however, you are free to specify another method: - - echo Form::open(array('url' => 'foo/bar', 'method' => 'put')) - -> **Note:** Since HTML forms only support `POST` and `GET`, `PUT` and `DELETE` methods will be spoofed by automatically adding a `_method` hidden field to your form. - -You may also open forms that point to named routes or controller actions: - - echo Form::open(array('route' => 'route.name')) - - echo Form::open(array('action' => 'Controller@method')) - -You may pass in route parameters as well: - - echo Form::open(array('route' => array('route.name', $user->id))) - - echo Form::open(array('action' => array('Controller@method', $user->id))) - -If your form is going to accept file uploads, add a `files` option to your array: - - echo Form::open(array('url' => 'foo/bar', 'files' => true)) - - -## CSRF Protection - -#### Adding The CSRF Token To A Form - -Laravel provides an easy method of protecting your application from cross-site request forgeries. First, a random token is placed in your user's session. Don't sweat it, this is done automatically. The CSRF token will be added to your forms as a hidden field automatically. However, if you wish to generate the HTML for the hidden field, you may use the `token` method: - - echo Form::token(); - -#### Attaching The CSRF Filter To A Route - - Route::post('profile', array('before' => 'csrf', function() - { - // - })); - - -## Form Model Binding - -#### Opening A Model Form - -Often, you will want to populate a form based on the contents of a model. To do so, use the `Form::model` method: - - echo Form::model($user, array('route' => array('user.update', $user->id))) - -Now, when you generate a form element, like a text input, the model's value matching the field's name will automatically be set as the field value. So, for example, for a text input named `email`, the user model's `email` attribute would be set as the value. However, there's more! If there is an item in the Session flash data matching the input name, that will take precedence over the model's value. So, the priority looks like this: - -1. Session Flash Data (Old Input) -2. Explicitly Passed Value -3. Model Attribute Data - -This allows you to quickly build forms that not only bind to model values, but easily re-populate if there is a validation error on the server! - -> **Note:** When using `Form::model`, be sure to close your form with `Form::close`! - - -## Labels - -#### Generating A Label Element - - echo Form::label('email', 'E-Mail Address'); - -#### Specifying Extra HTML Attributes - - echo Form::label('email', 'E-Mail Address', array('class' => 'awesome')); - -> **Note:** After creating a label, any form element you create with a name matching the label name will automatically receive an ID matching the label name as well. - - -## Text, Text Area, Password & Hidden Fields - -#### Generating A Text Input - - echo Form::text('username'); - -#### Specifying A Default Value - - echo Form::text('email', 'example@gmail.com'); - -> **Note:** The *hidden* and *textarea* methods have the same signature as the *text* method. - -#### Generating A Password Input - - echo Form::password('password'); - -#### Generating Other Inputs - - echo Form::email($name, $value = null, $attributes = array()); - echo Form::file($name, $attributes = array()); - - -## Checkboxes and Radio Buttons - -#### Generating A Checkbox Or Radio Input - - echo Form::checkbox('name', 'value'); - - echo Form::radio('name', 'value'); - -#### Generating A Checkbox Or Radio Input That Is Checked - - echo Form::checkbox('name', 'value', true); - - echo Form::radio('name', 'value', true); - - -## File Input - -#### Generating A File Input - - echo Form::file('image'); - -> **Note:** The form must have been opened with the `files` option set to `true`. - - -## Drop-Down Lists - -#### Generating A Drop-Down List - - echo Form::select('size', array('L' => 'Large', 'S' => 'Small')); - -#### Generating A Drop-Down List With Selected Default - - echo Form::select('size', array('L' => 'Large', 'S' => 'Small'), 'S'); - -#### Generating A Grouped List - - echo Form::select('animal', array( - 'Cats' => array('leopard' => 'Leopard'), - 'Dogs' => array('spaniel' => 'Spaniel'), - )); - -#### Generating A Drop-Down List With A Range - - echo Form::selectRange('number', 10, 20); - -#### Generating A List With Month Names - - echo Form::selectMonth('month'); - - -## Buttons - -#### Generating A Submit Button - - echo Form::submit('Click Me!'); - -> **Note:** Need to create a button element? Try the *button* method. It has the same signature as *submit*. - - -## Custom Macros - -#### Registering A Form Macro - -It's easy to define your own custom Form class helpers called "macros". Here's how it works. First, simply register the macro with a given name and a Closure: - - Form::macro('myField', function() - { - return ''; - }); - -Now you can call your macro using its name: - -#### Calling A Custom Form Macro - - echo Form::myField(); - - - -##Generating URLs - -For more information on generating URL's, check out the documentation on [helpers](helpers#urls.md). diff --git a/http-tests.md b/http-tests.md new file mode 100644 index 0000000..33ff0af --- /dev/null +++ b/http-tests.md @@ -0,0 +1,145 @@ +# HTTP Tests + +- [Introduction](#introduction) +- [Session / Authentication](#session-and-authentication) +- [Testing JSON APIs](#testing-json-apis) +- [Available Assertions](#available-assertions) + + +## Introduction + +Laravel provides a very fluent API for making HTTP requests to your application and examining the output. For example, take a look at the test defined below: + + get('/'); + + $response->assertStatus(200); + } + } + +The `get` method makes a `GET` request into the application, while the `assertStatus` method asserts that the returned response should have the given HTTP status code. In addition to this simple assertion, Laravel also contains a variety of assertions for inspecting the response headers, content, JSON structure, and more. + + +### Session / Authentication + +Laravel provides several helpers for working with the session during HTTP testing. First, you may set the session data to a given array using the `withSession` method. This is useful for loading the session with data before issuing a request to your application: + + withSession(['foo' => 'bar']) + ->get('/'); + } + } + +Of course, one common use of the session is for maintaining state for the authenticated user. The `actingAs` helper method provides a simple way to authenticate a given user as the current user. For example, we may use a [model factory](/docs/{{version}}/database-testing#writing-factories) to generate and authenticate a user: + + create(); + + $response = $this->actingAs($user) + ->withSession(['foo' => 'bar']) + ->get('/') + } + } + +You may also specify which guard should be used to authenticate the given user by passing the guard name as the second argument to the `actingAs` method: + + $this->actingAs($user, 'api') + + +### Testing JSON APIs + +Laravel also provides several helpers for testing JSON APIs and their responses. For example, the `json`, `get`, `post`, `put`, `patch`, and `delete` methods may be used to issue requests with various HTTP verbs. You may also easily pass data and headers to these methods. To get started, let's write a test to make a `POST` request to `/user` and assert that the expected data was returned: + + json('POST', '/user', ['name' => 'Sally']); + + $response + ->assertStatus(200) + ->assertJson([ + 'created' => true, + ]); + } + } + +> {tip} The `assertJson` method converts the response to an array and utilizes `PHPUnit::assertArraySubset` to verify that the given fragment exists within the JSON response returned by the application. So, if there are other properties in the JSON response, this test will still pass as long as the given fragment is present. + + +### Verifying Exact Match + +If you would like to verify that the given array is an **exact** match for the JSON returned by the application, you should use the `assertExactJson` method: + + json('POST', '/user', ['name' => 'Sally']); + + $response + ->assertStatus(200) + ->assertExactJson([ + 'created' => true, + ]); + } + } + + +### Available Assertions + +Laravel provides a variety of custom assertion methods for your [PHPUnit](https://phpunit.de/) tests. These assertions may be accessed on the response that is returned from the `json`, `get`, `post`, `put`, and `delete` test methods: + +Method | Description +------------- | ------------- +`$response->assertStatus($code);` | Assert that the response has a given code. +`$response->assertRedirect($uri);` | Assert that the response is a redirect to a given URI. +`$response->assertHeader($headerName, $value = null);` | Assert that the given header is present on the response. +`$response->assertCookie($cookieName, $value = null);` | Assert that the response contains the given cookie. +`$response->assertPlainCookie($cookieName, $value = null);` | Assert that the response contains the given cookie (unencrypted). +`$response->assertSessionHas($key, $value = null);` | Assert that the session contains the given piece of data. +`$response->assertSessionMissing($key);` | Assert that the session does not contain the given key. +`$response->assertJson(array $data);` | Assert that the response contains the given JSON data. +`$response->assertExactJson(array $data);` | Assert that the response contains an exact match of the given JSON data. +`$response->assertViewHas($key, $value = null);` | Assert that the response view was given a piece of data. diff --git a/installation.md b/installation.md index 5d2c8a4..db68b6d 100644 --- a/installation.md +++ b/installation.md @@ -1,83 +1,122 @@ -# Laravel install လုပ်ခြင်း +# Installation -- [Composer ကို Install လုပ်ခြင်း](#install-composer) -- [Laravel ကို Install လုပ်ခြင်း](#install-laravel) -- [Server လိုအပ်ချက်မျာ](#server-requirements) -- [Configuration လုပ်ခြင်း](#configuration) -- [URL လှလှလေးလိုချင်တယ်](#pretty-urls) +- [Installation](#installation) + - [Server Requirements](#server-requirements) + - [Installing Laravel](#installing-laravel) + - [Configuration](#configuration) +- [Web Server Configuration](#web-server-configuration) + - [Pretty URLs](#pretty-urls) - -## Composer ကို Install လုပ်ခြင်း + +## Installation -Laravel ရဲ့အသုံးဝင်တဲ့tool .... [Composer](http://getcomposer.org), သူ့ရဲ့ depenedencies တွေကို Manage လုပ်ဖို့။ ပထမဆုံး `composer.phar` copy ကိို download လုပ်လိုက်ပါ။ download လုပ်ပြီးသွားပြီဆိုရင် သင့်မှာ PHAR ဆိုတဲ့file လေးရှိသွားပါပြီ၊ အဲဒီ့ file ကိုသင့်ရဲ့local project မှာဒီတိုင်းထားချင်ရင်လည်းရပါတယ် တကယ်လို့သင်က `usr/local/bin` ထဲကိုရွှေ့ပြီးတော့သင့်ရဲ့ System အတွက် Global လုပ်မယ်ဆိုလည်းလုပ်နိုင်ပါတယ်။ Window မှာဆိုရင်တော့ [Windows installer](https://getcomposer.org/Composer-Setup.exe) ကိုသုံးပြီး install လုပ်နိုင်ပါတယ်။ +> {video} Are you a visual learner? Laracasts provides a [free, thorough introduction to Laravel](https://laracasts.com/series/laravel-from-scratch-2017) for newcomers to the framework. It's a great place to start your journey. - -## Laravel ကို Install လုပ်ခြင်း + +### Server Requirements -### Laravel Installer မှတစ်ဆင့် +The Laravel framework has a few system requirements. Of course, all of these requirements are satisfied by the [Laravel Homestead](/docs/{{version}}/homestead) virtual machine, so it's highly recommended that you use Homestead as your local Laravel development environment. -ပထမဆုံး[Laravel installer PHAR archive](http://laravel.com/laravel.phar) ကို download လုပ်ပါ၊ install လုပ်ရာမှာလွယ်ကူအောင်လို့ file name ကို `laravel` လို့ပြောင်းလိုက်ပါ၊ ပြောင်းပြီးသွားရင်အဲ့ဒီ့ File ကို `/usr/local/bin` ထဲကိုရွှေ့လိုက်ပါ။ Laravel ကို Install လုပ်မယ်ဆိုရင် `laravel new` ဆိုပြီး command line ကနေ run လိုက်ရင် Laravel Framework တစ်ခုကိုကိုယ်ကြိုက်တဲ့နေရာမှာ Install လုပ်နိုင်ပါပြီ။ `laravel new blog` ဆိုပြီး command line ကနေ run လိုက်ရင် blog ဆိုတဲ့အမည်နဲ့ command line ကနေကိုယ် create လုပ်ချင်တဲ့နေရာမှာ Laravel Framework အသစ်တစ်ခုကို install လုပ်ပေးမှာဖြစ်ပါတယ်။ ဒီနည်းက composer ကနေ download လုပ်တာထက်ပိုမြန်ပါတယ်။ +However, if you are not using Homestead, you will need to make sure your server meets the following requirements: -သင့်အနေနဲ့ Laravel ကို Composer ကနေတစ်ဆင့် `create-project` command သုံးပြီးတော့လည်း install လုပ်နိုင်ပါတယ်၊ terminal မှာ အောက်မှာရေးထားတဲ့ command ကို run ပြီးတော့လည်း install လုပ်နိုင်ပါတယ် +
    +- PHP >= 5.6.4 +- OpenSSL PHP Extension +- PDO PHP Extension +- Mbstring PHP Extension +- Tokenizer PHP Extension +- XML PHP Extension +
    - composer create-project laravel/laravel --prefer-dist + +### Installing Laravel -### Download မှတစ်ဆင့် +Laravel utilizes [Composer](https://getcomposer.org) to manage its dependencies. So, before using Laravel, make sure you have Composer installed on your machine. -Composer ကို install လုပ်ပြီးသွားပြီဆိုရင် Laravel Framework [latest version](https://github.com/laravel/laravel/archive/master.zip) ကို download လုပ်လိုက်ပါ၊ သင့်ရဲ့ web server ထဲမှာ zip ကို extra လုပ်လိုက်ပါ၊ extra လုပ်ထားတဲ့ framework folder ထဲကို command line ကဝင်ပြီးတော့ `php composer.phar install` ဒါမှမဟုတ် (`composer install`) ဆိုပြီး run လိုက်ပါ။ ဒီ command က framework ရဲ့ dependencies တွေကို install လုပ်ခိုင်းလိုက်တာပါ။ ဒီ installation လုပ်တဲ့နေရာမှာ webserver မှာ git install လုပ်ထားမှ successfully complete ဖြစ်မှာပါ။ +#### Via Laravel Installer -တကယ်လို့သင် Framework ကို update လုပ်ချင်တယ်ဆိုရင်`php composer.phar update` command ကို run ပေးရပါ့မယ်။ +First, download the Laravel installer using Composer: - -## Server လိုအပ်ချက်များ -Laravel Framework မှာ system requirements တစ်ချို့ရှိပါတယ်။ ဘာတွေလည်းဆိုရင် + composer global require "laravel/installer" + +Make sure to place the `$HOME/.composer/vendor/bin` directory (or the equivalent directory for your OS) in your $PATH so the `laravel` executable can be located by your system. + +Once installed, the `laravel new` command will create a fresh Laravel installation in the directory you specify. For instance, `laravel new blog` will create a directory named `blog` containing a fresh Laravel installation with all of Laravel's dependencies already installed: + + laravel new blog + +#### Via Composer Create-Project + +Alternatively, you may also install Laravel by issuing the Composer `create-project` command in your terminal: + + composer create-project --prefer-dist laravel/laravel blog + +#### Local Development Server -- PHP >= 5.3.7 -- MCrypt PHP Extension +If you have PHP installed locally and you would like to use PHP's built-in development server to serve your application, you may use the `serve` Artisan command. This command will start a development server at `http://localhost:8000`: -တို့ဘဲဖြစ်ပါတယ်။ + php artisan serve -PHP 5.5 မှာ တစ်ချို့ OS တွေက PHP JSON extension ကို manullly install လုပ်ပေးရပါတယ်။ တကယ်လို့ Ubuntu သုံးတယ်ဆိုရင် `apt-get install php5-json` ဆိုပြီး terminal ကနေ run လိုက်တာနဲ့အဆင်ပြေပါတယ်။ +Of course, more robust local development options are available via [Homestead](/docs/{{version}}/homestead) and [Valet](/docs/{{version}}/valet). -## Configuration လုပ်ခြင်း +### Configuration -Laravel က configuration ဆိုတာမရှိသလောက်ပါဘဲ။ သင်စပြီး develop ဖို့ရာအဆင်သင့်ပါဘဲ။ဘယ်လိုဘဲပြောပြော သင့်အနေနဲ့ `app/config/app.php` file နဲ့သူ့ရဲ့ Documencation ကိုပြန်ကြည့်ချင်မှာပါဘဲ။ `app/config/app.php`မှာဘာတွေပါသလဲဆိုရင်တော့ `timezone` နောက် `locale`တို့ပါပါတယ်၊သင့်ရဲ့ application နဲ့အဆင်ပြေတာတွေကို configure လုပ်နိုင်ပါတယ်။ +#### Public Directory -Laravel ကိုတစ်ခါ Install လုပ်တိုင်း [သင့်ရဲ့ local environmet](configuration#environment-configuration.md) ကို Configure ပြန်လုပ်သင့်ပါတယ်။ local machine မှာ develop လုပ်တဲ့အခါ erros ကိုမြင်ရမယ်။ မူလကတော့ error reporting က သင့်ရဲ့ development production မှာ disable လုပ်ထားပါတယ်။ +After installing Laravel, you should configure your web server's document / web root to be the `public` directory. The `index.php` in this directory serves as the front controller for all HTTP requests entering your application. -> **မှတ်ချက်:** `app.debug` ကို production မှာဘယ်တော့မှ true မပေးသင့်ပါဘူး။ဘယ်တော့မှ မလုပ်ပါနဲ့။ +#### Configuration Files - -### Permissions များ +All of the configuration files for the Laravel framework are stored in the `config` directory. Each option is documented, so feel free to look through the files and get familiar with the options available to you. -Laravel က `app/storage` ကို web server အတွက် permission write ပေးရပါမယ်။ +#### Directory Permissions - -### လမ်းကြောင်းများ +After installing Laravel, you may need to configure some permissions. Directories within the `storage` and the `bootstrap/cache` directories should be writable by your web server or Laravel will not run. If you are using the [Homestead](/docs/{{version}}/homestead) virtual machine, these permissions should already be set. -Framework ရဲ့ လမ်းကြောင်းတွေကပြောင်းလဲနိုင်ပါတယ်၊ ဒီ location တွေကိုပြောင်းချင်တယ်ဆိုရင် `bootstrap/paths.php` မှာကြည့်ရှူပြောင်းလည်းနိုင်ပါတယ်။ +#### Application Key + +The next thing you should do after installing Laravel is set your application key to a random string. If you installed Laravel via Composer or the Laravel installer, this key has already been set for you by the `php artisan key:generate` command. + +Typically, this string should be 32 characters long. The key can be set in the `.env` environment file. If you have not renamed the `.env.example` file to `.env`, you should do that now. **If the application key is not set, your user sessions and other encrypted data will not be secure!** + +#### Additional Configuration + +Laravel needs almost no other configuration out of the box. You are free to get started developing! However, you may wish to review the `config/app.php` file and its documentation. It contains several options such as `timezone` and `locale` that you may wish to change according to your application. + +You may also want to configure a few additional components of Laravel, such as: + +
    +- [Cache](/docs/{{version}}/cache#configuration) +- [Database](/docs/{{version}}/database#configuration) +- [Session](/docs/{{version}}/session#configuration) +
    + + +## Web Server Configuration -## URL လှလှလေးလိုချင်တယ် +### Pretty URLs -### Apache +#### Apache -Framework ထဲက `public/.htaccess` ကို URL မှာ `index.php` မပါအောင်ဖျောက်ထားပေးမှာဖြစ်ပါတယ်။ တကယ်လို့သင့် ရဲ့ Laravel application က Apache ကိုသုံးတယ်ဆိုရင် `mod_rewrite` ကို enable လုပ်ဖို့မမေ့ပါနဲ့ဦး။ +Laravel includes a `public/.htaccess` file that is used to provide URLs without the `index.php` front controller in the path. Before serving Laravel with Apache, be sure to enable the `mod_rewrite` module so the `.htaccess` file will be honored by the server. -တကယ်လို့ `.htaccess`file က သင့် Application မှာအလုပ်မလုပ်ဘူးဆိုရင် အောက်ကတစ်ခုကိုစမ်းကြည့်လိုက်ပါ: +If the `.htaccess` file that ships with Laravel does not work with your Apache installation, try this alternative: - Options +FollowSymLinks - RewriteEngine On + Options +FollowSymLinks + RewriteEngine On - RewriteCond %{REQUEST_FILENAME} !-d - RewriteCond %{REQUEST_FILENAME} !-f - RewriteRule ^ index.php [L] + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] -### Nginx +#### Nginx -Nginx မှာဆိုရင်အောက်ကညွှန်ကြားချက်ကို လိုက်လုပ်လိုက်တာနဲ့URL လှလှလေးတွေရပါတယ် +If you are using Nginx, the following directive in your site configuration will direct all requests to the `index.php` front controller: location / { try_files $uri $uri/ /index.php?$query_string; } + +Of course, when using [Homestead](/docs/{{version}}/homestead) or [Valet](/docs/{{version}}/valet), pretty URLs will be automatically configured. diff --git a/introduction.md b/introduction.md deleted file mode 100644 index 98bbadd..0000000 --- a/introduction.md +++ /dev/null @@ -1,25 +0,0 @@ -# Laravel Framework မိတ်ဆက် - - - [ဘယ်ကနေစမလဲ](#where-to-start) - - [Laravel သဘောတရား](#laravel-philosophy) - -## ဘယ်ကနေစမလဲ - -Framework အသစ်တစ်ခုကို လေ့လာရတာကိုလန့်နေနိုင်ပါတယ်၊ ဒါပေမယ့် ဒါဟာ ရင်ခုန်ဖို့အရမ်းကောင်းပါတယ်။ သင့်ရဲ့ အကူးအပြောင်းကိုအဆင်ပြေဖို့၊ ကျွန်တော်တို့က ကျစ်လျစ်ပြည့်စုံပြီး အရှင်းဆုံးဖြစ်အောင်ကြိုးပမ်းပြီးတော့ Laravel Documentation ကို ပြုလုပ်ထားပါတယ်။ဒီမှာအရင်ဖတ်သင့်တာတွေကို ဖော်ပြထားပါတယ်: - - - [Installation](installation.md) and - [Configuration](configuration.md) - - [Routing](routing.md) - - [Requests & Input](requests.md) - - [Views & Responses](responses.md) - - [Controllers](controllers.md) - -အပေါ်က Documention Link တွေကိုဖတ်ပြီးပြီဆိုရင် သင့် အနေနဲ့ Laravel ရဲ့ request/response တွေကို ကောင်းကောင်း ကိုယ်တွယ်ဖြေရှင်းနိုင်သင့်ပါတယ်။ နောက်ပြီး သင်အနေနဲ့ [Database Configuration](database) / [Eloquent ORM](/docs/eloquent) ဖတ်ဖို့ဆုတောင်းကောင်းဆုတောင်းနေမယ်လို့ထင်ပါတယ် အဲ့ဒီလိုမှမဟုတ်ဘူးဆိုရင် [authentication and security](/docs/security.md) ကိုပေါ့ ဒါမှလူတွေကို သင့်ရဲ့ application ထဲကို sign in ဝင်ခိုင်းလို့ရမှာကိုး။ - - - -## Laravel သဘောတရား - -Laravel က ရိုးရှင်းသပ်ရပ်၊ မဟာဆန်ပြီး လှပနေတဲ့ syntax တွေနဲ ့ ရေးသားထားတဲ့ Web Application Framework တစ်ခုဖြစ်ပါတယ်၊ ကျွန်တော်တို့ Development က ပျော်စရာ ကောင်းရမယ် ဆိုတာကိုယုံကြည်ပါတယ်။ ဖန်တီးမှု တွေကိုလည်း စိတ်ချမ်းသာမူ အပြည့်အဝ ပေးမယ်လို့ယုံကြည်ပါတယ်။ Laravel က Web projects တွေရဲ့အဓိကအလုပ်တွေဖြစ်တဲ့ authernication, routing, sessions, နဲ့ caching တွေကို တက်နိုင်သမျှ လျှော့ချဖို့ ကြိုးစားနေပါတယ်။ - -Laravel ကနားလည်လွယ်တယ်၊ ဟုတ်ပါတယ် powerful လည်းဖြစ်တယ်၊ နောက် ကြီးမားရှုပ်ထွေးတဲ့ Projects တွေအတွက်လည်း အကောင်းဆုံး tools တွေကိုထောက်ပံ့နေပါတယ်။ ထိပ်တန်း ခွဲစိတ်မှူတစ်ခု control container,expressive migration system နဲ့ tightly integrated unit testing support tools တွေကိုသင့်ကိုပေးထားပါတယ် သင် Create လုပ်ချင်တဲ့ Application ကိုသင်စိတ်ကြိုက်လုပ်နိုင်ပါတယ်။ diff --git a/ioc.md b/ioc.md deleted file mode 100644 index 56a7099..0000000 --- a/ioc.md +++ /dev/null @@ -1,186 +0,0 @@ -# IoC Container - -- [Introduction](#introduction) -- [Basic Usage](#basic-usage) -- [Where To Register Bindings](#where-to-register) -- [Automatic Resolution](#automatic-resolution) -- [Practical Usage](#practical-usage) -- [Service Providers](#service-providers) -- [Container Events](#container-events) - - -## Introduction - -The Laravel inversion of control container is a powerful tool for managing class dependencies. Dependency injection is a method of removing hard-coded class dependencies. Instead, the dependencies are injected at run-time, allowing for greater flexibility as dependency implementations may be swapped easily. - -Understanding the Laravel IoC container is essential to building a powerful, large application, as well as for contributing to the Laravel core itself. - - -## Basic Usage - -#### Binding A Type Into The Container - -There are two ways the IoC container can resolve dependencies: via Closure callbacks or automatic resolution. First, we'll explore Closure callbacks. First, a "type" may be bound into the container: - - App::bind('foo', function($app) - { - return new FooBar; - }); - -#### Resolving A Type From The Container - - $value = App::make('foo'); - -When the `App::make` method is called, the Closure callback is executed and the result is returned. - -#### Binding A "Shared" Type Into The Container - -Sometimes, you may wish to bind something into the container that should only be resolved once, and the same instance should be returned on subsequent calls into the container: - - App::singleton('foo', function() - { - return new FooBar; - }); - -#### Binding An Existing Instance Into The Container - -You may also bind an existing object instance into the container using the `instance` method: - - $foo = new Foo; - - App::instance('foo', $foo); - - -## Where To Register Bindings - -IoC bindings, like event handlers or route filters, generally fall under the title of "bootstrap code". In other words, they prepare your application to actually handle requests, and usually need to be executed before a route or controller is actually called. Like most other bootstrap code, the `start` files are always an option for registering IoC bindings. Alternatively, you could create an `app/ioc.php` (filename does not matter) file and require that file from your `start` file. - -If your application has a very large number of IoC bindings, or you simply wish to organize your IoC bindings in separate files by category, you may register your bindings in a [service provider](#service-providers). - - -## Automatic Resolution - -#### Resolving A Class - -The IoC container is powerful enough to resolve classes without any configuration at all in many scenarios. For example: - - class FooBar { - - public function __construct(Baz $baz) - { - $this->baz = $baz; - } - - } - - $fooBar = App::make('FooBar'); - -Note that even though we did not register the FooBar class in the container, the container will still be able to resolve the class, even injecting the `Baz` dependency automatically! - -When a type is not bound in the container, it will use PHP's Reflection facilities to inspect the class and read the constructor's type-hints. Using this information, the container can automatically build an instance of the class. - -#### Binding An Interface To An Implementation - -However, in some cases, a class may depend on an interface implementation, not a "concrete type". When this is the case, the `App::bind` method must be used to inform the container which interface implementation to inject: - - App::bind('UserRepositoryInterface', 'DbUserRepository'); - -Now consider the following controller: - - class UserController extends BaseController { - - public function __construct(UserRepositoryInterface $users) - { - $this->users = $users; - } - - } - -Since we have bound the `UserRepositoryInterface` to a concrete type, the `DbUserRepository` will automatically be injected into this controller when it is created. - - -## Practical Usage - -Laravel provides several opportunities to use the IoC container to increase the flexibility and testability of your application. One primary example is when resolving controllers. All controllers are resolved through the IoC container, meaning you can type-hint dependencies in a controller constructor, and they will automatically be injected. - -#### Type-Hinting Controller Dependencies - - class OrderController extends BaseController { - - public function __construct(OrderRepository $orders) - { - $this->orders = $orders; - } - - public function getIndex() - { - $all = $this->orders->all(); - - return View::make('orders', compact('all')); - } - - } - -In this example, the `OrderRepository` class will automatically be injected into the controller. This means that when [unit testing](testing.md) a "mock" `OrderRepository` may be bound into the container and injected into the controller, allowing for painless stubbing of database layer interaction. - -#### Other Examples Of IoC Usage - -[Filters](routing#route-filters), [composers](/docs/responses#view-composers), and [event handlers](/docs/events#using-classes-as-listeners.md) may also be resolved out of the IoC container. When registering them, simply give the name of the class that should be used: - - Route::filter('foo', 'FooFilter'); - - View::composer('foo', 'FooComposer'); - - Event::listen('foo', 'FooHandler'); - - -## Service Providers - -Service providers are a great way to group related IoC registrations in a single location. Think of them as a way to bootstrap components in your application. Within a service provider, you might register a custom authentication driver, register your application's repository classes with the IoC container, or even setup a custom Artisan command. - -In fact, most of the core Laravel components include service providers. All of the registered service providers for your application are listed in the `providers` array of the `app/config/app.php` configuration file. - -#### Defining A Service Provider - -To create a service provider, simply extend the `Illuminate\Support\ServiceProvider` class and define a `register` method: - - use Illuminate\Support\ServiceProvider; - - class FooServiceProvider extends ServiceProvider { - - public function register() - { - $this->app->bind('foo', function() - { - return new Foo; - }); - } - - } - -Note that in the `register` method, the application IoC container is available to you via the `$this->app` property. Once you have created a provider and are ready to register it with your application, simply add it to the `providers` array in your `app` configuration file. - -#### Registering A Service Provider At Run-Time - -You may also register a service provider at run-time using the `App::register` method: - - App::register('FooServiceProvider'); - - -## Container Events - -#### Registering A Resolving Listener - -The container fires an event each time it resolves an object. You may listen to this event using the `resolving` method: - - App::resolvingAny(function($object) - { - // - }); - - App::resolving('foo', function($foo) - { - // - }); - -Note that the object that was resolved will be passed to the callback. diff --git a/license.md b/license.md index 90ceb8b..aa1f3d4 100644 --- a/license.md +++ b/license.md @@ -1,4 +1,4 @@ -MIT လိုင်စင်(MIT) +The MIT License (MIT) Copyright © Taylor Otwell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/lifecycle.md b/lifecycle.md old mode 100755 new mode 100644 index d9aaa7e..27e0da9 --- a/lifecycle.md +++ b/lifecycle.md @@ -1,80 +1,50 @@ # Request Lifecycle -- [Overview](#overview) -- [Request Lifecycle](#request-lifecycle) -- [Start Files](#start-files) -- [Application Events](#application-events) +- [Introduction](#introduction) +- [Lifecycle Overview](#lifecycle-overview) +- [Focus On Service Providers](#focus-on-service-providers) - -## Overview + +## Introduction -သင် tools တစ်ခုကို တကယ်လက်တွေ့သုံးပြီဆိုရင် အဲ့ဒီ tool က ဘယ်လိုအလုပ်လုပ်တယ်ဆိုတာကိုသိရင် သင်ပိုပြီး ယုံကြည်မှူရှိလာပါလိမ့်မယ်။ development tools တွေရဲ့ function တွေဘယ်လိုအလုပ်လုပ်လဲသင်သိလာတဲ့အခါမှာ သင်အဲဒါတွေကိုအသုံးပြုတဲ့အခါပိုပြီးတော့ အဆင်ပြေ ယုံကြည်လာပါလိမ့်မယ်။ ဒီ document ရဲ့ အဓိကရည်ရွယ်ချက်က Laravel Framework ဘယ်လိုအလုပ်လုပ်လဲဆိုတာကို ကောင်းမွန်တဲ့ hight-level overview တစ်ခုပေးဖို့ပါ။ Framework အကြောင်း overview ကောင်းကောင်းသိသွားတဲ့အချိန်မှာ "magical" လို့ထင်တာတွေနည်းသွားပြီးတော့ သင် application တည်ဆောက်ရာမှာပိုပြီးတော့ confident ရှိလာပါလိမ့်မယ်။ Request Lifecycle ရဲ့ hight level overview ရဲ့ဖြည့်စွတ်ချက်မှာတော့ "start" files နဲ့ application events ကိုပါ cover လုပ်ထားပါတယ်။ +When using any tool in the "real world", you feel more confident if you understand how that tool works. Application development is no different. When you understand how your development tools function, you feel more comfortable and confident using them. -တကယ်လို့သင့်အနေနဲ့ terms အားလုံးကိုနားမလည်ဘူးဆိုရင်စိတ်ထဲမထားပါနဲ့ ။ အခြေခံအားဖြင့် ဘယ်လိုလုပ်နေလဲဆိုတာကို ကြိုးစားကြည့်ပြီး documencation ရဲ့တစ်ခြား အပိုင်းတွေကို ဖတ်ပြီး သင့်ပိုပြီးသိလာပါလိမ့်မယ်။ +The goal of this document is to give you a good, high-level overview of how the Laravel framework works. By getting to know the overall framework better, everything feels less "magical" and you will be more confident building your applications. If you don't understand all of the terms right away, don't lose heart! Just try to get a basic grasp of what is going on, and your knowledge will grow as you explore other sections of the documentation. - -## Request Lifecycle + +## Lifecycle Overview -သင့် application ရဲ့ Request အားလုံးကို `public/index.php` ဆီကို redirect လုပ်ပါတယ်။ Apache ကိုအသုံးပြုတဲ့အခါမှာ `.htaccess` files က request အားလုံးကို `index.php` စီ redirect လုပ်ပေးပါတယ်။ အဲ့ဒီ့ကနေစပြီးတော့ Laravel က request တွေကိုလက်ခံတာ response တွေကို client ဆီပြန်ပေးတာတွေကို handles လုပ်ပေးသွားတာပါ၊ Laravel ရဲ့ bootstrap general idea က အသုံးဝင်ပါလိမ့်မယ် ၊ ဒါကြောင့်ကျွန်တော်တို့အခု အောက်မှာရှင်းပြပါ့မယ်။ +### First Things -Laravel ရဲ့ bootstrap process လေ့လာတဲ့နေရာမှာ **Service Providers** ကအဓိကဖြစ်ပါတယ်။ Services Providers တွေရဲ့ Lists တွေကို `app/config/app.php` ကိုဖွင့်ပြီး `providers` arrays မှာရှာတွေ့နိုင်ပါတယ်။ ဒီ providers တွေက Laravel ကို bootstrap လုပ်ဖို့ အဓိက ဖြစ်ပါတယ်။ သင့် `index.php` file ကို request တစ်ခုလုပ်လိုက်တာနဲ့ `bootstrap/start.php` က load လုပ်ပါမယ်။ အဲ့ဒီ့ file က Laravel `Application` object တွေကို create လုပ်ပါ့မယ်၊ နောက် [Ioc container](ioc.md) ကိုလည်း serve လုပ်ပါတယ်။ +The entry point for all requests to a Laravel application is the `public/index.php` file. All requests are directed to this file by your web server (Apache / Nginx) configuration. The `index.php` file doesn't contain much code. Rather, it is simply a starting point for loading the rest of the framework. -`Application` ရဲ့ object တွေကို create လုပ်ပြီးပြီဆိုရင်တော့ project ရဲ့ paths အချို့ကိုစတင်ပြီး တပ်ဆင်ပါ့မယ်၊ နောက် [environment detection](configuration#environment-configuration.md) တွေကိုဆက်လက်လုပ်ဆောင်ပါတယ်။ ဒါပြီးရင်တော့ Laravel bootstrap script တွေကို call လုပ်ပါ့မယ်။ Laravel source ရဲ့တွင်းပိုင်း File တွေထိ live ဖြစ်သွားပြီဆိုရင် သင့်ရဲ့ configuration ပေါ်မူတည်ပြီး setting တွေကို တပ်ဆင်ပါလိမ့်မယ်။ timezoneတို့၊ error reporting နဲ့ အခြား လိုအပ်တဲ့ setting တွေပေါ့။ ဒါပေမယ့် သင့် Application လိုအပ်တဲ့ Service Provider များအားလုံးကို register လုပ်ထားဖို့ကလည်း အခြား configuration တွေအားလုံးလိုပဲ အရေးကြီးပါတယ်။ +The `index.php` file loads the Composer generated autoloader definition, and then retrieves an instance of the Laravel application from `bootstrap/app.php` script. The first action taken by Laravel itself is to create an instance of the application / [service container](/docs/{{version}}/container). -Simple service providers only have one method: `register`. This `register` method is called when the service provider is registered with the application object via the application's own `register` method. Within this method, service providers register things with the [IoC container](ioc). Essentially, each service provider binds one or more [closures](http://us3.php.net/manual/en/functions.anonymous.php) into the container, which allows you to access those bound services within your application. So, for example, the `QueueServiceProvider` registers closures that resolve the various [Queue](/docs/queues.md) related classes. Of course, service providers may be used for any bootstrapping task, not just registering things with the IoC container. A service provider may register event listeners, view composers, Artisan commands, and more. +### HTTP / Console Kernels -Service Providers တွေအကုန်လုံး register လုပ်ပြီးရင် သင့်ရဲ့ `app/start` file loadလုပ်ပါလိမ့်မယ်။ နောက်ဆုံးအနေနဲ့သင့်ရဲ့ `app/routes.php` ကို load လုပ်ပါ့မယ်။ နောက်တစ်ခါသင့် application ရဲ့ `route.php` load လုပ်ပြီးရင် request objects တွေသင့် application ဆီကိုပို့ပါမယ်၊ ဒါက route တွေကိုစေလွှတ်ခြင်းဖြစ်ပါလိမ့်မယ်။ +Next, the incoming request is sent to either the HTTP kernel or the console kernel, depending on the type of request that is entering the application. These two kernels serve as the central location that all requests flow through. For now, let's just focus on the HTTP kernel, which is located in `app/Http/Kernel.php`. -ကဲဒါဆိုရင်အတိုချုပ်လိုက်ကြရအောင်: +The HTTP kernel extends the `Illuminate\Foundation\Http\Kernel` class, which defines an array of `bootstrappers` that will be run before the request is executed. These bootstrappers configure error handling, configure logging, [detect the application environment](/docs/{{version}}/configuration#environment-configuration), and perform other tasks that need to be done before the request is actually handled. -1. Request တွေက `public/index.php` file ဆီကို ဝင်ရောက်လာတယ် -2. `bootstrap/start.php` file က Application ကို create လုပ်ပြီးတော့ environment ကို detect လုပ်တယ် -3. အတွင်းပိုင်း `framework/start.php` file က setting တွေကို configure လုပ်တယ်နောက်တော့ service providers တွေကို load လုပ်တယ် -4. Application ရဲ့ `app/start` file တွေ load လုပ်တယ် -5. Application ရဲ့ `app/route` file load လုပ်တယ် -6. Request objects တွေကို application ဆီကို ပို့တယ်၊ အဲဒီ့ကနေ object တွေ Response ပြန်လာတယ် -7. ပြန်လာတဲ့ Response တွေကို client ဆီကိုပြန်ပို့တယ် +The HTTP kernel also defines a list of HTTP [middleware](/docs/{{version}}/middleware) that all requests must pass through before being handled by the application. These middleware handle reading and writing the [HTTP session](/docs/{{version}}/session), determining if the application is in maintenance mode, [verifying the CSRF token](/docs/{{version}}/csrf), and more. -အခု Laravel က application ရဲ့ Request တွေကိုဘယ်လိုဖြေရှင်းသွားတယ်ဆိုတာသိပြီးသွားပြီ `start` file အကြောင်းကို နည်းနည်းအသေးစိတ်ဆက်လေ့လာလိုက်ကြအောင်။ +The method signature for the HTTP kernel's `handle` method is quite simple: receive a `Request` and return a `Response`. Think of the Kernel as being a big black box that represents your entire application. Feed it HTTP requests and it will return HTTP responses. - -## Start Files +#### Service Providers -သင့် Application ရဲ့ Start Files တွေက `app/start` ထဲမှာပါ။ Default အရဆိုရင် သင့် application ရဲ့ `global.php`,`local.php` နဲ့ `artisan.php` တို့ပါဝင်ပါတယ်။ artisan အကြောင်းအသေးစိတ်သိလိုတယ်ဆိုရင်တော့ [Artisan command line](command#registering-commands.md) ကိုဖတ်ဖို့ညွှန်းပရစေ။ +One of the most important Kernel bootstrapping actions is loading the [service providers](/docs/{{version}}/providers) for your application. All of the service providers for the application are configured in the `config/app.php` configuration file's `providers` array. First, the `register` method will be called on all providers, then, once all providers have been registered, the `boot` method will be called. -Default အရ`global.php` မှာ basic items တွေပါဝင်ပါတယ်၊ registration တွေရဲ့ [logger](errors.md) တို့... နောက် `app/filters.php` တို့လည်းပါဝင်ပါသေးတယ်။ ဒါပေမယ့်လည်း ဒီ `global.php` မှာ သင်ကြိုက်တဲ့ File တွေထက်ထည့်လို့ရပါတယ်။ တကယ်လို့ထက်ထည့်လိုက်ရင် အဲ့ဒီ့ File က သင့် application ရဲ့ request တိုင်းမှာ auto ပါဝင်နေမှာပါ။ `local.php` file ကတော့ `local` environment မှာမှ call လုပ်မှာပါ၊ -Environment configuration အကြောင်းအသေးစိတ်သိလိုတယ်ဆိုရင်တော့ [configuration](configuration.md) ကိုဖတ်ဖို့ ညွှန်းပရစေ။ +Service providers are responsible for bootstrapping all of the framework's various components, such as the database, queue, validation, and routing components. Since they bootstrap and configure every feature offered by the framework, service providers are the most important aspect of the entire Laravel bootstrap process. -ဟုတ်တာပေါ့ သင့်မှာ `local` environment တစ်ခုအပြင်အခြား environment တစ်ခုရှိတယ်ဆိုရင် အဲ့ဒီ့ environment အတွက် start file တစ်ခု create လုပ်ရမှာပေါ့။ နောက်အဲ့ဒီ့ start မှာပါတာတွေက သင်အဲ့ဒီ့ environment မှာအလုပ်လုပ်တဲ့အခါမှာ အလိုလိုပါလာမှပါ။ ဒါကြောင့် ..... ဥပမာ- သင့်မှာ `developemt` environment တစ်ခုရှပြီးတော့ `bootstrap/start.php` မှာ configre လုပ်ပြီးပြီဆိုရင် သင်အနေနဲ့ `app/start/development.php` file တစ်ခု create လုပ်ထားတယ်ဆိုရင် သင့် application က အဲ့ဒီ့ environment မှာ run ရင် `app/start/development.php` ကအလိုလိုပါဝင်နေမှာပါ။ +#### Dispatch Request -### What To Place In Start Files +Once the application has been bootstrapped and all service providers have been registered, the `Request` will be handed off to the router for dispatching. The router will dispatch the request to a route or controller, as well as run any route specific middleware. -Start files ကရိုးရိုးနေရာပါဘဲ...."bootstrapping" code တွေထည့်ရတဲ့နေရာပေါ့ ။ ဥပမာ၊ View composerတို့၊ logging preferences တွေကို configure လုပ်တာတို့ PHP Setting တွေပြောင်းတာ..နဲ့အခြားလိုအပ်တာတွေကို သင့် register လုပ်ချင်ရင်လဲလုပ်နိုင်ပါတယ်။ ဘာတွေကို register လုပ်ချင်လဲဆိုတာကတော့ သင့်အပေါ်မှာဘဲမူတည်ပါတယ်။ ဟုတ်တာပေါ့ "bootstrapping code" တွေအကုန်လုံးကိုသင့်ရဲ့ start file ထဲကိုထည့်လိုက်ရင် သင့်ရဲ့ start file တွေရှုပ်ပွကုန်မှာပေါ့။Application နည်းနည်းကြီးလာပြီဆိုရင် ဒါမှမဟုတ် သင့်ရဲ့ start files နည်းနည်းရှုပ်လာပြီလို့ခံစားရပြီဆိုရင်... bootstrapping code တွေကို [service providers](ioc#service-providers.md) တွေဆီရွှေ့လိုက်ပါ။ + +## Focus On Service Providers - -## Application Events +Service providers are truly the key to bootstrapping a Laravel application. The application instance is created, the service providers are registered, and the request is handed to the bootstrapped application. It's really that simple! -#### Registering Application Events +Having a firm grasp of how a Laravel application is built and bootstrapped via service providers is very valuable. Of course, your application's default service providers are stored in the `app/Providers` directory. -သင့်အနေနဲ့ pre request ၊ post request တွေစနစ်တစ်ကျသွားဖို့အတွက် before, after, finish, and shutdown application events တွေကိုသုံးရပါ့မယ် - - App::before(function($request) - { - // - }); - - App::after(function($request, $response) - { - // - }); - -အဲ့ဒီ့ event တွေပေါ်မူတည်ပြီးတော့ `before` နဲ့ `after` request တွေကို တစ်လှည့်ဆီသင့် application က run မှာပါ။ ဒီ events တွေက global filtering နဲ့ global modification တွေရဲ့ responses တွေအတွက်အလွန်အသုံးဝင်ပါလိမ့်မယ်။ သင့်အနေနဲ့ အဲ့ဒါတွေကို `start` files ဒါမှမဟုတ် [service provider](ioc#service-providers.md) မှာ register လုပ်ထားနိုင်ပါတယ်။ - -`matched` event ပေါ်က listener တစ်ခုကိုလည်း register လုပ်နိုင်ပါတယ်၊ request အဝင်တစ်ခုနဲ့ route တစ်ခုနဲ့ matched ဖြစ်သွားပြီဆိုရင် အဲဒါက fired လုပ်လိုက်တယ် ဒါပေမယ့် အဲ့ဒီ့ route က excute ဖြစ်မသွားပါဘူး။ - - Route::matched(function($route, $request) - { - // - }); - -သင် application က client ဆီကို sent လုပ်ပြီးသွားပြီဆိုရင် နောက်ဆုံး `finish` event ကို call လုပ်ပါတယ်။ သင် application ရဲ့နောက်ဆုံးမိနစ်လိုအပ်ချက်တွေကိုလုပ်ဖို့ဒါကနေရာကောင်းတစ်ခုပါ။ `finish` event handlers က အားလုံးပြီးသွားပြီဆိုရင် `shutdown` event ကိုချက်ချင်းခေါ်လိုက်ပါတယ်၊ ဒါကနောက်ဆုံး script အလုပ်မလုပ်ခင် လုပ်စရာရှိတာလုပ်ထားဖို့ နောက်ဆုံးအခွင့်အရေးပါ။ +By default, the `AppServiceProvider` is fairly empty. This provider is a great place to add your application's own bootstrapping and service container bindings. Of course, for large applications, you may wish to create several service providers, each with a more granular type of bootstrapping. diff --git a/localization.md b/localization.md old mode 100755 new mode 100644 index eece9c0..075487c --- a/localization.md +++ b/localization.md @@ -1,109 +1,146 @@ # Localization -- [မိတ်ဆက်](#introduction) -- [Language Files](#language-files) -- [အခြေခံအသုံးပြုခြင်း](#basic-usage) -- [အများကိန်းပြုခြင်း](#pluralization) -- [Validation Localization](#validation) +- [Introduction](#introduction) +- [Defining Translation Strings](#defining-translation-strings) + - [Using Short Keys](#using-short-keys) + - [Using Translation Strings As Keys](#using-translation-strings-as-keys) +- [Retrieving Translation Strings](#retrieving-translation-strings) + - [Replacing Parameters In Translation Strings](#replacing-parameters-in-translation-strings) + - [Pluralization](#pluralization) - [Overriding Package Language Files](#overriding-package-language-files) -## မိတ်ဆက် +## Introduction -Laravel မှာပါတဲ့ `Lang` class ဟာ languages ဖိုင်တွေထဲမှာသတ်မှတ်ထားတဲ့ စကားစုတွေကို လွယ်ကူ အဆင်ပြေသော နည်းလမ်းတွေနဲ့ လက်ခံဆောင်ရွက်ပေးနိုင်ပါတယ်။ သင့် application အတွက် ဘာသာစကားမျိုးစုံကို လွယ်ကူစွာ အသုံးပြုနိုင်အောင်အထောက်အပံ့ပေးထားပါတယ်။ +Laravel's localization features provide a convenient way to retrieve strings in various languages, allowing you to easily support multiple languages within your application. Language strings are stored in files within the `resources/lang` directory. Within this directory there should be a subdirectory for each language supported by the application: - -## Language Files + /resources + /lang + /en + messages.php + /es + messages.php -`app/lang` လမ်းကြောင်းအောက်မှာ ဘာသာစကား စကားစုတွေကို သိမ်းဆည်းပါတယ်။ အဲ့ဒီလမ်းကြောင်းအောက်မှာတော့ သတ်မှတ်ချင်တဲ့ ဘာသာစကားတစ်ခုချင်းစီအတွက် ဖိုဒါတစ်ခုချင်းစီ ဆောက်ပြီးအသုံးပြုရမှာပါ။ +All language files simply return an array of keyed strings. For example: - /app - /lang - /en - messages.php - /mm - messages.php + 'Welcome to our application' + ]; -ဘာသာစကားသတ်မှတ်ထားတဲ့ ဖိုင်ဆီကနေ keyed strings တွေပါတဲ့ array return ပြန်လာပါတယ်။ ဥပမာ - +### Configuring The Locale - 'Welcome to our application' - ); + Route::get('welcome/{locale}', function ($locale) { + App::setLocale($locale); -#### Changing The Default Language At Runtime + // + }); -Application ရဲ့ ပုံမှန် ဘာသာစကားကိုတော့ `app/config/app.php` configuration ဖိုင်ထဲမှာ သတ်မှတ်ထားပါတယ်။ ဘာသာစကားများ တစ်ခုနဲ့တစ်ခု ပြောင်းလဲ အသုံးပြုချင်ရင်တော့ `App::setLocale` method ကိုအသုံးပြုနိုင်ပါတယ်။ +You may configure a "fallback language", which will be used when the active language does not contain a given translation string. Like the default language, the fallback language is also configured in the `config/app.php` configuration file: - App::setLocale('mm'); + 'fallback_locale' => 'en', -#### Setting The Fallback Language +#### Determining The Current Locale -"fallback language" အတွက်လည်း ပြင်ဆင်ထားနိုင်ပါတယ်။ "fallback language" ဆိုတာကတော့ လက်ရှိ သတ်မှတ်ထားတဲ့ ဘာသာစကား (language) ဖိုင်မှာ လိုအပ်နေတဲ့ စကားစု (language line) မပါလာတဲ့ အခြေအနေမျိုးမှာ အသုံးပြုဖို့အတွက်ဖြစ်ပါတယ်။ ပုံမှန်သတ်မှတ်နေကျအတိုင်းပဲ "fallback language" ကို `app/config/app.php` configuration ဖိုင်ထဲမှာသတ်မှတ်နိုင်ပါတယ်။ +You may use the `getLocale` and `isLocale` methods on the `App` facade to determine the current locale or check if the locale is a given value: - 'fallback_locale' => 'en', + $locale = App::getLocale(); - -## အခြေခံအသုံးပြုနည်း + if (App::isLocale('en')) { + // + } -#### ဘာသာစကားသတ်မှတ်ထားသော ဖိုင်မှ စကားစုများ ရယူခြင်း + +## Defining Translation Strings - echo Lang::get('messages.welcome'); + +### Using Short Keys -`get`method ထဲကို passed လုပ်ထားတဲ့ string နှစ်ခုထဲမှ ပထမတစ်ခုကတော့ ဘာသာစကား (language) သတ်မှတ်ထားတဲ့ ဖိုင်ရဲ့ အမည်ဖြစ်ပြီး၊ ဒုတိယ တစ်ခုကတော့ array ထဲမှာသတ်မှတ်ထား စကားစုတွေရဲ့ key ဖြစ်ပါတယ်။ +Typically, translation strings are stored in files within the `resources/lang` directory. Within this directory there should be a subdirectory for each language supported by the application: -> **သတိပြုရန်**: အကယ်၍ `get` နဲ့ ယူထားတဲ့ key အတွက် စကားစုဟာ ရှိမနေဘူးဆိုရင်တော့ key တစ်ခုပဲ return ပြန်လာပါလိမ့်မယ်။ + /resources + /lang + /en + messages.php + /es + messages.php -`trans` ဆိုတဲ့ helper function ကိုလည်း အသုံးပြုနိုင်ပါတယ်။ အဲ့ဒီ function ကတော့ `Lang::get` ဆိုတဲ့ method ကိုပဲ နာမည်ပြောင်းပြီးထပ်လုပ်ထားတာပါ။ +All language files simply return an array of keyed strings. For example: - echo trans('messages.welcome'); + 'Welcome to our application' + ]; - 'welcome' => 'Welcome, :name', + +### Using Translation Strings As Keys -ပြီးရင်တော့ `Lang::get` method ရဲ့ ဒုတိယ argument မှာ အစားထိုးချင်တဲ့ စကားလုံးကို passing ပေးလိုက်ပါ။ +For applications with heavy translation requirements, defining every string with a "short key" can become quickly confusing when referencing them in your views. For this reason, Laravel also provides support for defining translation strings using the "default" translation of the string as the key. - echo Lang::get('messages.welcome', array('name' => 'Dayle')); +Translation files that use translation strings as keys are stored as JSON files in the `resources/lang` directory. For example, if your application has a Spanish translation, you should create a `resources/lang/es.json` file: -#### Determine If A Language File Contains A Line + { + "I love programming.": "Me encanta la programación." + } - if (Lang::has('messages.welcome')) - { - // - } + +## Retrieving Translation Strings - -## အများကိန်းပြုလုပ်ခြင်း +You may retrieve lines from language files using the `__` helper function. The `__` method accepts the file and key of the translation string as its first argument. For example, let's retrieve the `welcome` translation string from the `resources/lang/messages.php` language file: + + echo __('messages.welcome'); + + echo __('I love programming.'); + +Of course if you are using the [Blade templating engine](/docs/{{version}}/blade), you may use the `{{ }}` syntax to echo the translation string or use the `@lang` directive: -အများကိန်းပြုလုပ်ခြင်းကိစ္စ ဟာ နည်းနည်းတော့ ရှုပ်ထွေးပါတယ်။ မတူညီတဲ့ languages တွေအတွက် မတူညီတဲ့ အများကိန်းပြုလုပ်နည်းတွေ ရှိပါတယ်။ Laravel မှာတော့ အများကိန်းပြုလုပ်ဖို့အတွက် "pipe" character ကို အနည်းကိန်းအတွက် ပြုလုပ်ထားတဲ့ စကားစုနဲ့ အများကိန်းအတွက်သတ်မှတ်မဲ့ စကားစုကြားမှာ ခံပြီးအသုံးပြုနိုင်ပါတယ်။ အများကိန်းပြုလုပ်တာကိုနားလည်ဖို့အတွက် အောက်ပါ ဥပမာကိုကြည့်ပါ။ + {{ __('messages.welcome') }} - 'apples' => 'There is one apple|There are many apples', + @lang('messages.welcome') -စကားစုတွေကို ယူသုံးဖို့အတွက်တော့ `Lang::choice` mehtod ကိုအသုံးပြုနိုင်ပါတယ်။ +If the specified translation string does not exist, the `__` function will simply return the translation string key. So, using the example above, the `__` function would return `messages.welcome` if the translation string does not exist. - echo Lang::choice('messages.apples', 10); + +### Replacing Parameters In Translation Strings -Local အတွက်သတ်မှတ်ထားတဲ့ စကားလုံးကိုလဲ သတ်မှတ်ပေးလိုက်နိုင်ပါတယ်။ ဥပမာ - Russian (ru) language ကိုအသုံးပြုချင်တယ်ဆိုရင် - +If you wish, you may define place-holders in your translation strings. All place-holders are prefixed with a `:`. For example, you may define a welcome message with a place-holder name: - echo Lang::choice('товар|товара|товаров', $count, array(), 'ru'); + 'welcome' => 'Welcome, :name', -Laravel translator ဟာ Symfony Translation component ကိုအသုံးပြုထားတဲ့အတွက်ကြောင့် သင့်အနေနဲ့ ပိုပြီး ရှင်းလင်းတိကျတဲ့ အများကိန်းပြုနည်း သတ်မှတ်ချက်ကို ပြုလုပ်နိုင်ပါတယ်။ +To replace the place-holders when retrieving a translation string, pass an array of replacements as the second argument to the `__` function: - 'apples' => '{0} There are none|[1,19] There are some|[20,Inf] There are many', + echo __('messages.welcome', ['name' => 'dayle']); +If your place-holder contains all capital letters, or only has its first letter capitalized, the translated value will be capitalized accordingly: - -## Validation + 'welcome' => 'Welcome, :NAME', // Welcome, DAYLE + 'goodbye' => 'Goodbye, :Name', // Goodbye, Dayle + + + +### Pluralization -Localization အတွက် အသုံးပြုနိုင်တဲ့ validation errors နဲ့ messages တွေကိုတော့ အသုံးပြုနည်း လမ်းညွှန်ရဲ့Validation မှာ ကြည့်နိုင်ပါတယ်။ +Pluralization is a complex problem, as different languages have a variety of complex rules for pluralization. By using a "pipe" character, you may distinguish singular and plural forms of a string: + + 'apples' => 'There is one apple|There are many apples', + +You may even create more complex pluralization rules which specify translation strings for multiple number ranges: + + 'apples' => '{0} There are none|[1,19] There are some|[20,*] There are many', + +After defining a translation string that has pluralization options, you may use the `trans_choice` function to retrieve the line for a given "count". In this example, since the count is greater than one, the plural form of the translation string is returned: + + echo trans_choice('messages.apples', 10); ## Overriding Package Language Files -Laravel နဲ့အတူ တွဲစပ်အသုံးပြုနိုင်တဲ့ packages တွေမှာ သူတို့ရဲ့ ကိုယ်ပိုင် ဘာသာစကားဖိုင်တွေတစ်ပါတည်းပါလာပါတယ်။ အဲ့ဒီဖိုင်တွေကို change ဖို့ packages တွေရဲ့ မူရင်းဖိုင်တွေကို သွားပြင်နေမဲ့အစား `app/lang/packages/{locale}/{package}` လမ်းကြောင်းအောက်ကနေတစ်ဆင့် override ပြုလုပ်နိုင်ပါတယ်။ ဥပမာ `skyrim/hearthfire` လို့ အမည်တွင်တဲ့ package အတွက် `messages.php` ဖိုင်ထဲမှာရှိတဲ့ English Language ကို override လုပ်ချင်တယ်ဆိုရင် `app/lang/packages/en/hearthfire/messages.php` ဖိုင်ကနေတစ်ဆင့် ပြုလုပ်နိုင်ပါတယ်။ Override လုပ်ဖို့လိုအပ်တဲ့ စကားစုတွေကိုပဲ အဲ့ဒီဖိုင်ထဲမှာသတ်မှတ်ထားဖို့လိုအပ်ပါတယ်။ ကျန်တဲ့စကားစုအားလုံးကိုတော့ package ရဲ့ language ဖိုင်ထဲက နေပဲ အလုပ်လုပ်သွားမှာဖြစ်ပါတယ်။ +Some packages may ship with their own language files. Instead of changing the package's core files to tweak these lines, you may override them by placing files in the `resources/lang/vendor/{package}/{locale}` directory. + +So, for example, if you need to override the English translation strings in `messages.php` for a package named `skyrim/hearthfire`, you should place a language file at: `resources/lang/vendor/hearthfire/en/messages.php`. Within this file, you should only define the translation strings you wish to override. Any translation strings you don't override will still be loaded from the package's original language files. diff --git a/mail.md b/mail.md old mode 100755 new mode 100644 index a0cd992..d0968d7 --- a/mail.md +++ b/mail.md @@ -1,136 +1,523 @@ # Mail -- [Configuration](#configuration) -- [Basic Usage](#basic-usage) -- [Embedding Inline Attachments](#embedding-inline-attachments) -- [Queueing Mail](#queueing-mail) +- [Introduction](#introduction) + - [Driver Prerequisites](#driver-prerequisites) +- [Generating Mailables](#generating-mailables) +- [Writing Mailables](#writing-mailables) + - [Configuring The Sender](#configuring-the-sender) + - [Configuring The View](#configuring-the-view) + - [View Data](#view-data) + - [Attachments](#attachments) + - [Inline Attachments](#inline-attachments) +- [Markdown Mailables](#markdown-mailables) + - [Generating Markdown Mailables](#generating-markdown-mailables) + - [Writing Markdown Messages](#writing-markdown-messages) + - [Customizing The Components](#customizing-the-components) +- [Sending Mail](#sending-mail) + - [Queueing Mail](#queueing-mail) - [Mail & Local Development](#mail-and-local-development) +- [Events](#events) - -## Configuration + +## Introduction -Laravel provides a clean, simple API over the popular [SwiftMailer](http://swiftmailer.org) library. The mail configuration file is `app/config/mail.php`, and contains options allowing you to change your SMTP host, port, and credentials, as well as set a global `from` address for all messages delivered by the library. You may use any SMTP server you wish. If you wish to use the PHP `mail` function to send mail, you may change the `driver` to `mail` in the configuration file. A `sendmail` driver is also available. +Laravel provides a clean, simple API over the popular [SwiftMailer](http://swiftmailer.org) library with drivers for SMTP, Mailgun, SparkPost, Amazon SES, PHP's `mail` function, and `sendmail`, allowing you to quickly get started sending mail through a local or cloud based service of your choice. -### API Drivers + +### Driver Prerequisites -Laravel also includes drivers for the Mailgun and Mandrill HTTP APIs. These APIs are often simpler and quicker than the SMTP servers. Both of these drivers require that the Guzzle 4 HTTP library be installed into your application. You can add Guzzle 4 to your project by adding the following line to your `composer.json` file: +The API based drivers such as Mailgun and SparkPost are often simpler and faster than SMTP servers. If possible, you should use one of these drivers. All of the API drivers require the Guzzle HTTP library, which may be installed via the Composer package manager: - "guzzlehttp/guzzle": "~4.0" + composer require guzzlehttp/guzzle #### Mailgun Driver -To use the Mailgun driver, set the `driver` option to `mailgun` in your `app/config/mail.php` configuration file. Next, create an `app/config/services.php` configuration file if one does not already exist for your project. Verify that it contains the following options: +To use the Mailgun driver, first install Guzzle, then set the `driver` option in your `config/mail.php` configuration file to `mailgun`. Next, verify that your `config/services.php` configuration file contains the following options: - 'mailgun' => array( - 'domain' => 'your-mailgun-domain', - 'secret' => 'your-mailgun-key', - ), + 'mailgun' => [ + 'domain' => 'your-mailgun-domain', + 'secret' => 'your-mailgun-key', + ], -#### Mandrill Driver +#### SparkPost Driver -To use the Mailgun driver, set the `driver` option to `mandrill` in your `app/config/mail.php` configuration file. Next, create an `app/config/services.php` configuration file if one does not already exist for your project. Verify that it contains the following options: +To use the SparkPost driver, first install Guzzle, then set the `driver` option in your `config/mail.php` configuration file to `sparkpost`. Next, verify that your `config/services.php` configuration file contains the following options: - 'mandrill' => array( - 'secret' => 'your-mandrill-key', - ), + 'sparkpost' => [ + 'secret' => 'your-sparkpost-key', + ], -### Log Driver +#### SES Driver -If the `driver` option of your `app/config/mail.php` configuration file is set to `log`, all e-mails will be written to your log files, and will not actually be sent to any of the recipients. This is primarily useful for quick, local debugging and content verification. +To use the Amazon SES driver you must first install the Amazon AWS SDK for PHP. You may install this library by adding the following line to your `composer.json` file's `require` section and running the `composer update` command: - -## Basic Usage + "aws/aws-sdk-php": "~3.0" -The `Mail::send` method may be used to send an e-mail message: +Next, set the `driver` option in your `config/mail.php` configuration file to `ses` and verify that your `config/services.php` configuration file contains the following options: - Mail::send('emails.welcome', $data, function($message) - { - $message->to('foo@example.com', 'John Smith')->subject('Welcome!'); - }); + 'ses' => [ + 'key' => 'your-ses-key', + 'secret' => 'your-ses-secret', + 'region' => 'ses-region', // e.g. us-east-1 + ], -The first argument passed to the `send` method is the name of the view that should be used as the e-mail body. The second is the `$data` that should be passed to the view, and the third is a Closure allowing you to specify various options on the e-mail message. + +## Generating Mailables -> **Note:** A `$message` variable is always passed to e-mail views, and allows the inline embedding of attachments. So, it is best to avoid passing a `message` variable in your view payload. +In Laravel, each type of email sent by your application is represented as a "mailable" class. These classes are stored in the `app/Mail` directory. Don't worry if you don't see this directory in your application, since it will be generated for you when you create your first mailable class using the `make:mail` command: -You may also specify a plain text view to use in addition to an HTML view: + php artisan make:mail OrderShipped - Mail::send(array('html.view', 'text.view'), $data, $callback); + +## Writing Mailables -Or, you may specify only one type of view using the `html` or `text` keys: +All of a mailable class' configuration is done in the `build` method. Within this method, you may call various methods such as `from`, `subject`, `view`, and `attach` to configure the email's presentation and delivery. - Mail::send(array('text' => 'view'), $data, $callback); + +### Configuring The Sender -You may specify other options on the e-mail message such as any carbon copies or attachments as well: +#### Using The `from` Method - Mail::send('emails.welcome', $data, function($message) - { - $message->from('us@example.com', 'Laravel'); +First, let's explore configuring the sender of the email. Or, in other words, who the email is going to be "from". There are two ways to configure the sender. First, you may use the `from` method within your mailable class' `build` method: - $message->to('foo@example.com')->cc('bar@example.com'); + /** + * Build the message. + * + * @return $this + */ + public function build() + { + return $this->from('example@example.com') + ->view('emails.orders.shipped'); + } - $message->attach($pathToFile); - }); +#### Using A Global `from` Address -When attaching files to a message, you may also specify a MIME type and / or a display name: +However, if your application uses the same "from" address for all of its emails, it can become cumbersome to call the `from` method in each mailable class you generate. Instead, you may specify a global "from" address in your `config/mail.php` configuration file. This address will be used if no other "from" address is specified within the mailable class: - $message->attach($pathToFile, array('as' => $display, 'mime' => $mime)); + 'from' => ['address' => 'example@example.com', 'name' => 'App Name'], -> **Note:** The message instance passed to a `Mail::send` Closure extends the SwiftMailer message class, allowing you to call any method on that class to build your e-mail messages. + +### Configuring The View - -## Embedding Inline Attachments +Within a mailable class' `build` method, you may use the `view` method to specify which template should be used when rendering the email's contents. Since each email typically uses a [Blade template](/docs/{{version}}/blade) to render its contents, you have the full power and convenience of the Blade templating engine when building your email's HTML: -Embedding inline images into your e-mails is typically cumbersome; however, Laravel provides a convenient way to attach images to your e-mails and retrieving the appropriate CID. + /** + * Build the message. + * + * @return $this + */ + public function build() + { + return $this->view('emails.orders.shipped'); + } -#### Embedding An Image In An E-Mail View +> {tip} You may wish to create a `resources/views/emails` directory to house all of your email templates; however, you are free to place them wherever you wish within your `resources/views` directory. - - Here is an image: +#### Plain Text Emails - - +If you would like to define a plain-text version of your email, you may use the `text` method. Like the `view` method, the `text` method accepts a template name which will be used to render the contents of the email. You are free to define both a HTML and plain-text version of your message: -#### Embedding Raw Data In An E-Mail View + /** + * Build the message. + * + * @return $this + */ + public function build() + { + return $this->view('emails.orders.shipped') + ->text('emails.orders.shipped_plain'); + } - - Here is an image from raw data: + +### View Data - - +#### Via Public Properties -Note that the `$message` variable is always passed to e-mail views by the `Mail` class. +Typically, you will want to pass some data to your view that you can utilize when rendering the email's HTML. There are two ways you may make data available to your view. First, any public property defined on your mailable class will automatically be made available to the view. So, for example, you may pass data into your mailable class' constructor and set that data to public properties defined on the class: + + order = $order; + } + + /** + * Build the message. + * + * @return $this + */ + public function build() + { + return $this->view('emails.orders.shipped'); + } + } + +Once the data has been set to a public property, it will automatically be available in your view, so you may access it like you would access any other data in your Blade templates: + +
    + Price: {{ $order->price }} +
    + +#### Via The `with` Method: + +If you would like to customize the format of your email's data before it is sent to the template, you may manually pass your data to the view via the `with` method. Typically, you will still pass data via the mailable class' constructor; however, you should set this data to `protected` or `private` properties so the data is not automatically made available to the template. Then, when calling the `with` method, pass an array of data that you wish to make available to the template: + + order = $order; + } + + /** + * Build the message. + * + * @return $this + */ + public function build() + { + return $this->view('emails.orders.shipped') + ->with([ + 'orderName' => $this->order->name, + 'orderPrice' => $this->order->price, + ]); + } + } + +Once the data has been passed to the `with` method, it will automatically be available in your view, so you may access it like you would access any other data in your Blade templates: + +
    + Price: {{ $orderPrice }} +
    + + +### Attachments + +To add attachments to an email, use the `attach` method within the mailable class' `build` method. The `attach` method accepts the full path to the file as its first argument: + + /** + * Build the message. + * + * @return $this + */ + public function build() + { + return $this->view('emails.orders.shipped') + ->attach('/path/to/file'); + } + +When attaching files to a message, you may also specify the display name and / or MIME type by passing an `array` as the second argument to the `attach` method: + + /** + * Build the message. + * + * @return $this + */ + public function build() + { + return $this->view('emails.orders.shipped') + ->attach('/path/to/file', [ + 'as' => 'name.pdf', + 'mime' => 'application/pdf', + ]); + } + +#### Raw Data Attachments + +The `attachData` method may be used to attach a raw string of bytes as an attachment. For example, you might use this method if you have generated a PDF in memory and want to attach it to the email without writing it to disk. The `attachData` method accepts the raw data bytes as its first argument, the name of the file as its second argument, and an array of options as its third argument: + + /** + * Build the message. + * + * @return $this + */ + public function build() + { + return $this->view('emails.orders.shipped') + ->attachData($this->pdf, 'name.pdf', [ + 'mime' => 'application/pdf', + ]); + } + + +### Inline Attachments + +Embedding inline images into your emails is typically cumbersome; however, Laravel provides a convenient way to attach images to your emails and retrieving the appropriate CID. To embed an inline image, use the `embed` method on the `$message` variable within your email template. Laravel automatically makes the `$message` variable available to all of your email templates, so you don't need to worry about passing it in manually: + + + Here is an image: + + + + +#### Embedding Raw Data Attachments + +If you already have a raw data string you wish to embed into an email template, you may use the `embedData` method on the `$message` variable: + + + Here is an image from raw data: + + + + + +## Markdown Mailables + +Markdown mailable messages allow you to take advantage of the pre-built templates and components of mail notifications in your mailables. Since the messages are written in Markdown, Laravel is able to render beautiful, responsive HTML templates for the messages while also automatically generating a plain-text counterpart. + + +### Generating Markdown Mailables + +To generate a mailable with a corresponding Markdown template, you may use the `--markdown` option of the `make:mail` Artisan command: + + php artisan make:mail OrderShipped --markdown=emails.orders.shipped + +Then, when configuring the mailable within its `build` method, call the `markdown` method instead of the `view` method. The `markdown` methods accepts the name of the Markdown template and an optional array of data to make available to the template: + + /** + * Build the message. + * + * @return $this + */ + public function build() + { + return $this->from('example@example.com') + ->markdown('emails.orders.shipped'); + } + + +### Writing Markdown Messages + +Markdown mailables use a combination of Blade components and Markdown syntax which allow you to easily construct mail messages while leveraging Laravel's pre-crafted components: + + @component('mail::message') + # Order Shipped + + Your order has been shipped! + + @component('mail::button', ['url' => $url]) + View Order + @endcomponent + + Thanks,
    + {{ config('app.name') }} + @endcomponent + +#### Button Component + +The button component renders a centered button link. The component accepts two arguments, a `url` and an optional `color`. Supported colors are `blue`, `green`, and `red`. You may add as many button components to a message as you wish: + + @component('mail::button', ['url' => $url, 'color' => 'green']) + View Order + @endcomponent + +#### Panel Component + +The panel component renders the given block of text in a panel that has a slightly different background color than the rest of the message. This allows you to draw attention to a given block of text: + + @component('mail::panel') + This is the panel content. + @endcomponent + +#### Table Component + +The table component allows you to transform a Markdown table into an HTML table. The component accepts the Markdown table as its content. Table column alignment is supported using the default Markdown table alignment syntax: + + @component('mail::table') + | Laravel | Table | Example | + | ------------- |:-------------:| --------:| + | Col 2 is | Centered | $10 | + | Col 3 is | Right-Aligned | $20 | + @endcomponent + + +### Customizing The Components + +You may export all of the Markdown mail components to your own application for customization. To export the components, use the `vendor:publish` Artisan command to publish the `laravel-mail` asset tag: + + php artisan vendor:publish --tag=laravel-mail + +This command will publish the Markdown mail components to the `resources/views/vendor/mail` directory. The `mail` directory will contain a `html` and a `markdown` directory, each containing their respective representations of every available component. You are free to customize these components however you like. + +#### Customizing The CSS + +After exporting the components, the `resources/views/vendor/mail/html/themes` directory will contain a `default.css` file. You may customize the CSS in this file and your styles will automatically be in-lined within the HTML representations of your Markdown mail messages. + +> {tip} If you would like to build an entirely new theme for the Markdown components, simply write a new CSS file within the `html/themes` directory and change the `theme` option of your `mail` configuration file. + + +## Sending Mail + +To send a message, use the `to` method on the `Mail` [facade](/docs/{{version}}/facades). The `to` method accepts an email address, a user instance, or a collection of users. If you pass an object or collection of objects, the mailer will automatically use their `email` and `name` properties when setting the email recipients, so make sure these attributes are available on your objects. Once you have specified your recipients, you may pass an instance of your mailable class to the `send` method: + + user())->send(new OrderShipped($order)); + } + } + +Of course, you are not limited to just specifying the "to" recipients when sending a message. You are free to set "to", "cc", and "bcc" recipients all within a single, chained method call: + + Mail::to($request->user()) + ->cc($moreUsers) + ->bcc($evenMoreUsers) + ->send(new OrderShipped($order)); -## Queueing Mail +### Queueing Mail #### Queueing A Mail Message -Since sending e-mail messages can drastically lengthen the response time of your application, many developers choose to queue e-mail messages for background sending. Laravel makes this easy using its built-in [unified queue API](queues.md). To queue a mail message, simply use the `queue` method on the `Mail` class: +Since sending email messages can drastically lengthen the response time of your application, many developers choose to queue email messages for background sending. Laravel makes this easy using its built-in [unified queue API](/docs/{{version}}/queues). To queue a mail message, use the `queue` method on the `Mail` facade after specifying the message's recipients: - Mail::queue('emails.welcome', $data, function($message) - { - $message->to('foo@example.com', 'John Smith')->subject('Welcome!'); - }); + Mail::to($request->user()) + ->cc($moreUsers) + ->bcc($evenMoreUsers) + ->queue(new OrderShipped($order)); -You may also specify the number of seconds you wish to delay the sending of the mail message using the `later` method: +This method will automatically take care of pushing a job onto the queue so the message is sent in the background. Of course, you will need to [configure your queues](/docs/{{version}}/queues) before using this feature. - Mail::later(5, 'emails.welcome', $data, function($message) - { - $message->to('foo@example.com', 'John Smith')->subject('Welcome!'); - }); +#### Delayed Message Queueing -If you wish to specify a specific queue or "tube" on which to push the message, you may do so using the `queueOn` and `laterOn` methods: +If you wish to delay the delivery of a queued email message, you may use the `later` method. As its first argument, the `later` method accepts a `DateTime` instance indicating when the message should be sent: - Mail::queueOn('queue-name', 'emails.welcome', $data, function($message) - { - $message->to('foo@example.com', 'John Smith')->subject('Welcome!'); - }); + $when = Carbon\Carbon::now()->addMinutes(10); + + Mail::to($request->user()) + ->cc($moreUsers) + ->bcc($evenMoreUsers) + ->later($when, new OrderShipped($order)); + +#### Pushing To Specific Queues + +Since all mailable classes generated using the `make:mail` command make use of the `Illuminate\Bus\Queueable` trait, you may call the `onQueue` and `onConnection` methods on any mailable class instance, allowing you to specify the connection and queue name for the message: + + $message = (new OrderShipped($order)) + ->onConnection('sqs') + ->onQueue('emails'); + + Mail::to($request->user()) + ->cc($moreUsers) + ->bcc($evenMoreUsers) + ->queue($message); + +#### Queueing By Default + +If you have mailable classes that you want to always be queued, you may implement the `ShouldQueue` contract on the class. Now, even if you call the `send` method when mailing, the mailable will still be queued since it implements the contract: + + use Illuminate\Contracts\Queue\ShouldQueue; + + class OrderShipped extends Mailable implements ShouldQueue + { + // + } ## Mail & Local Development -When developing an application that sends e-mail, it's usually desirable to disable the sending of messages from your local or development environment. To do so, you may either call the `Mail::pretend` method, or set the `pretend` option in the `app/config/mail.php` configuration file to `true`. When the mailer is in `pretend` mode, messages will be written to your application's log files instead of being sent to the recipient. +When developing an application that sends email, you probably don't want to actually send emails to live email addresses. Laravel provides several ways to "disable" the actual sending of emails during local development. + +#### Log Driver + +Instead of sending your emails, the `log` mail driver will write all email messages to your log files for inspection. For more information on configuring your application per environment, check out the [configuration documentation](/docs/{{version}}/configuration#environment-configuration). + +#### Universal To + +Another solution provided by Laravel is to set a universal recipient of all emails sent by the framework. This way, all the emails generated by your application will be sent to a specific address, instead of the address actually specified when sending the message. This can be done via the `to` option in your `config/mail.php` configuration file: + + 'to' => [ + 'address' => 'example@example.com', + 'name' => 'Example' + ], + +#### Mailtrap + +Finally, you may use a service like [Mailtrap](https://mailtrap.io) and the `smtp` driver to send your email messages to a "dummy" mailbox where you may view them in a true email client. This approach has the benefit of allowing you to actually inspect the final emails in Mailtrap's message viewer. + + +## Events + +Laravel fires an event just before sending mail messages. Remember, this event is fired when the mail is *sent*, not when it is queued. You may register an event listener for this event in your `EventServiceProvider`: -#### Enabling Pretend Mail Mode + /** + * The event listener mappings for the application. + * + * @var array + */ + protected $listen = [ + 'Illuminate\Mail\Events\MessageSending' => [ + 'App\Listeners\LogSentMessage', + ], + ]; - Mail::pretend(); \ No newline at end of file diff --git a/middleware.md b/middleware.md new file mode 100644 index 0000000..10f5d6a --- /dev/null +++ b/middleware.md @@ -0,0 +1,250 @@ +# Middleware + +- [Introduction](#introduction) +- [Defining Middleware](#defining-middleware) +- [Registering Middleware](#registering-middleware) + - [Global Middleware](#global-middleware) + - [Assigning Middleware To Routes](#assigning-middleware-to-routes) + - [Middleware Groups](#middleware-groups) +- [Middleware Parameters](#middleware-parameters) +- [Terminable Middleware](#terminable-middleware) + + +## Introduction + +Middleware provide a convenient mechanism for filtering HTTP requests entering your application. For example, Laravel includes a middleware that verifies the user of your application is authenticated. If the user is not authenticated, the middleware will redirect the user to the login screen. However, if the user is authenticated, the middleware will allow the request to proceed further into the application. + +Of course, additional middleware can be written to perform a variety of tasks besides authentication. A CORS middleware might be responsible for adding the proper headers to all responses leaving your application. A logging middleware might log all incoming requests to your application. + +There are several middleware included in the Laravel framework, including middleware for authentication and CSRF protection. All of these middleware are located in the `app/Http/Middleware` directory. + + +## Defining Middleware + +To create a new middleware, use the `make:middleware` Artisan command: + + php artisan make:middleware CheckAge + +This command will place a new `CheckAge` class within your `app/Http/Middleware` directory. In this middleware, we will only allow access to the route if the supplied `age` is greater than 200. Otherwise, we will redirect the users back to the `home` URI. + + age <= 200) { + return redirect('home'); + } + + return $next($request); + } + + } + +As you can see, if the given `age` is less than or equal to `200`, the middleware will return an HTTP redirect to the client; otherwise, the request will be passed further into the application. To pass the request deeper into the application (allowing the middleware to "pass"), simply call the `$next` callback with the `$request`. + +It's best to envision middleware as a series of "layers" HTTP requests must pass through before they hit your application. Each layer can examine the request and even reject it entirely. + +### Before & After Middleware + +Whether a middleware runs before or after a request depends on the middleware itself. For example, the following middleware would perform some task **before** the request is handled by the application: + + +## Registering Middleware + + +### Global Middleware + +If you want a middleware to run during every HTTP request to your application, simply list the middleware class in the `$middleware` property of your `app/Http/Kernel.php` class. + + +### Assigning Middleware To Routes + +If you would like to assign middleware to specific routes, you should first assign the middleware a key in your `app/Http/Kernel.php` file. By default, the `$routeMiddleware` property of this class contains entries for the middleware included with Laravel. To add your own, simply append it to this list and assign it a key of your choosing. For example: + + // Within App\Http\Kernel Class... + + protected $routeMiddleware = [ + 'auth' => \Illuminate\Auth\Middleware\Authenticate::class, + 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, + 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, + 'can' => \Illuminate\Auth\Middleware\Authorize::class, + 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, + 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, + ]; + +Once the middleware has been defined in the HTTP kernel, you may use the `middleware` method to assign middleware to a route: + + Route::get('admin/profile', function () { + // + })->middleware('auth'); + +You may also assign multiple middleware to the route: + + Route::get('/', function () { + // + })->middleware('first', 'second'); + +When assigning middleware, you may also pass the fully qualified class name: + + use App\Http\Middleware\CheckAge; + + Route::get('admin/profile', function () { + // + })->middleware(CheckAge::class); + + +### Middleware Groups + +Sometimes you may want to group several middleware under a single key to make them easier to assign to routes. You may do this using the `$middlewareGroups` property of your HTTP kernel. + +Out of the box, Laravel comes with `web` and `api` middleware groups that contains common middleware you may want to apply to your web UI and API routes: + + /** + * The application's route middleware groups. + * + * @var array + */ + protected $middlewareGroups = [ + 'web' => [ + \App\Http\Middleware\EncryptCookies::class, + \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, + \Illuminate\Session\Middleware\StartSession::class, + \Illuminate\View\Middleware\ShareErrorsFromSession::class, + \App\Http\Middleware\VerifyCsrfToken::class, + \Illuminate\Routing\Middleware\SubstituteBindings::class, + ], + + 'api' => [ + 'throttle:60,1', + 'auth:api', + ], + ]; + +Middleware groups may be assigned to routes and controller actions using the same syntax as individual middleware. Again, middleware groups simply make it more convenient to assign many middleware to a route at once: + + Route::get('/', function () { + // + })->middleware('web'); + + Route::group(['middleware' => ['web']], function () { + // + }); + +> {tip} Out of the box, the `web` middleware group is automatically applied to your `routes/web.php` file by the `RouteServiceProvider`. + + +## Middleware Parameters + +Middleware can also receive additional parameters. For example, if your application needs to verify that the authenticated user has a given "role" before performing a given action, you could create a `CheckRole` middleware that receives a role name as an additional argument. + +Additional middleware parameters will be passed to the middleware after the `$next` argument: + + user()->hasRole($role)) { + // Redirect... + } + + return $next($request); + } + + } + +Middleware parameters may be specified when defining the route by separating the middleware name and parameters with a `:`. Multiple parameters should be delimited by commas: + + Route::put('post/{id}', function ($id) { + // + })->middleware('role:editor'); + + +## Terminable Middleware + +Sometimes a middleware may need to do some work after the HTTP response has been sent to the browser. For example, the "session" middleware included with Laravel writes the session data to storage after the response has been sent to the browser. If you define a `terminate` method on your middleware, it will automatically be called after the response is sent to the browser. + + -## အစပျိုး +## Introduction -Migration မှာ Database အတွက် Version Control ပြုလုပ်နိုင်ရန် ဖန်တီးထားသည်။ ၄င်းကို အသုံးပြုခြင်းဖြင့် database schema များကို အလွယ်တကူ ပြင်ဆင်နိုင်ပြီး team တစ်ခုလုံး တူညီသည့် database schema ကို အသုံးပြုနိုင်ရန် ပံပိုးထားသည်။ Migrations မှာ ပှံမှန်အားဖြင့် [Schema Builder](schema.md) ဖြင့် တွဲဖက် အသုံးပြုကြသည်။ +Migrations are like version control for your database, allowing your team to easily modify and share the application's database schema. Migrations are typically paired with Laravel's schema builder to easily build your application's database schema. If you have ever had to tell a teammate to manually add a column to their local database schema, you've faced the problem that database migrations solve. - -## Migrations ဖန်တီးခြင်း +The Laravel `Schema` [facade](/docs/{{version}}/facades) provides database agnostic support for creating and manipulating tables across all of Laravel's supported database systems. -migration တစ်ခု ဖန်တီးနိုင်ရန် Artisan CLI တွင် `migrate:make` ဟူသည် command ကို အသုံးပြုနိုင်သည်။ + +## Generating Migrations - php artisan migrate:make create_users_table +To create a migration, use the `make:migration` [Artisan command](/docs/{{version}}/artisan): -Migration file များသည် `app/database/migrations` ဆိုသည့် folder တွင်တည်ရှိမည် ဖြစ်ပြီး Migrations များကို အစဉ်အတိုင်း စီရီထားမည့် timestamp ဖြင့် သတ်မှတ်ထားမည် ဖြစ်သည်။ + php artisan make:migration create_users_table -Migration တစ်ခု ဖန်တီးနေစဉ် `--path` ဟု attribute ကို အသုံးပြုနိုင်သည်။ အဆိုပါ path မှာ သင် install လုပ်ထားသော root directory မှ အလိုအလျောက် သိရှိမည် ဖြစ်ပါသည်။ +The new migration will be placed in your `database/migrations` directory. Each migration file name contains a timestamp which allows Laravel to determine the order of the migrations. - php artisan migrate:make foo --path=app/migrations +The `--table` and `--create` options may also be used to indicate the name of the table and whether the migration will be creating a new table. These options simply pre-fill the generated migration stub file with the specified table: - -`--table` နှင့် `--create` options များကို အသုံးပြု၍ table အမည်ကို သတ်မှတ်ခြင်း ၊ table အသစ်ကို ဖန်တီးခြင်း များ ပြုလုပ်နိုင်ပါမည်။ + php artisan make:migration create_users_table --create=users - php artisan migrate:make add_votes_to_user_table --table=users + php artisan make:migration add_votes_to_users_table --table=users - php artisan migrate:make create_users_table --create=users +If you would like to specify a custom output path for the generated migration, you may use the `--path` option when executing the `make:migration` command. The given path should be relative to your application's base path. - -## Migrations ပြုလုပ်ခြင်း + +## Migration Structure + +A migration class contains two methods: `up` and `down`. The `up` method is used to add new tables, columns, or indexes to your database, while the `down` method should simply reverse the operations performed by the `up` method. -#### Migration ကို အပြည့်အဝ ပြုလုပ်ခြင်း +Within both of these methods you may use the Laravel schema builder to expressively create and modify tables. To learn about all of the methods available on the `Schema` builder, [check out its documentation](#creating-tables). For example, this migration example creates a `flights` table: - php artisan migrate + increments('id'); + $table->string('name'); + $table->string('airline'); + $table->timestamps(); + }); + } -#### Package တစ်ခုအတွက် Migration ပြုလုပ်ခြင်း + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('flights'); + } + } + + + +## Running Migrations - php artisan migrate --package=vendor/package +To run all of your outstanding migrations, execute the `migrate` Artisan command: -> **သတိပြုရန်:** migrations run နေစဉ် "class not found" ဟု error တွေ ့ရှိပါက `composer dump-autoload` ဆိုသည့် command ကို run ကြည့်ပါ။ + php artisan migrate -### Production တွင် Migration ပြုလုပ်ခြင်း +> {note} If you are using the [Homestead virtual machine](/docs/{{version}}/homestead), you should run this command from within your virtual machine. -အချို ့သော migration operations များမှာ အန္တာရယ်များလှပေသည်။ တနည်းအားဖြင့် သင့်၏ အချက်အလက်များကို စက္ကန် ့ပိုင်းအတွင် ဆုံးရှုံးသွားစေနိုင်သည်။ အဆိုပါ အန္တာရယ်မှ ကာကွယ်နိုင်ရန် production အခြေအနေတွင် migration ပြုလုပ်ရန် confirmation တောင်းခံပါသည်။ ထိုတောင်းခံမှုကို ကျော်လွှားလိုပါက `--force` flag ကို အသုံးပြုနိုင်သည်။ +#### Forcing Migrations To Run In Production - php artisan migrate --force +Some migration operations are destructive, which means they may cause you to lose data. In order to protect you from running these commands against your production database, you will be prompted for confirmation before the commands are executed. To force the commands to run without a prompt, use the `--force` flag: + + php artisan migrate --force -## Rolling Back Migrations +### Rolling Back Migrations + +To rollback the latest migration operation, you may use the `rollback` command. This command rolls back the last "batch" of migrations, which may include multiple migration files: + + php artisan migrate:rollback + +You may rollback a limited number of migrations by providing the `step` option to the `rollback` command. For example, the following command will rollback the last five migrations: + + php artisan migrate:rollback --step=5 + +The `migrate:reset` command will roll back all of your application's migrations: + + php artisan migrate:reset + +#### Rollback & Migrate In Single Command + +The `migrate:refresh` command will roll back all of your migrations and then execute the `migrate` command. This command effectively re-creates your entire database: + + php artisan migrate:refresh + + // Refresh the database and run all database seeds... + php artisan migrate:refresh --seed + +You may rollback & re-migrate a limited number of migrations by providing the `step` option to the `refresh` command. For example, the following command will rollback & re-migrate the last five migrations: + + php artisan migrate:refresh --step=5 + + +## Tables + + +### Creating Tables + +To create a new database table, use the `create` method on the `Schema` facade. The `create` method accepts two arguments. The first is the name of the table, while the second is a `Closure` which receives a `Blueprint` object that may be used to define the new table: + + Schema::create('users', function (Blueprint $table) { + $table->increments('id'); + }); + +Of course, when creating the table, you may use any of the schema builder's [column methods](#creating-columns) to define the table's columns. + +#### Checking For Table / Column Existence + +You may easily check for the existence of a table or column using the `hasTable` and `hasColumn` methods: + + if (Schema::hasTable('users')) { + // + } + + if (Schema::hasColumn('users', 'email')) { + // + } + +#### Connection & Storage Engine + +If you want to perform a schema operation on a database connection that is not your default connection, use the `connection` method: + + Schema::connection('foo')->create('users', function (Blueprint $table) { + $table->increments('id'); + }); + +You may use the `engine` property on the schema builder to define the table's storage engine: + + Schema::create('users', function (Blueprint $table) { + $table->engine = 'InnoDB'; + + $table->increments('id'); + }); + + +### Renaming / Dropping Tables + +To rename an existing database table, use the `rename` method: + + Schema::rename($from, $to); + +To drop an existing table, you may use the `drop` or `dropIfExists` methods: + + Schema::drop('users'); + + Schema::dropIfExists('users'); + +#### Renaming Tables With Foreign Keys + +Before renaming a table, you should verify that any foreign key constraints on the table have an explicit name in your migration files instead of letting Laravel assign a convention based name. Otherwise, the foreign key constraint name will refer to the old table name. + + +## Columns + + +### Creating Columns + +The `table` method on the `Schema` facade may be used to update existing tables. Like the `create` method, the `table` method accepts two arguments: the name of the table and a `Closure` that receives a `Blueprint` instance you may use to add columns to the table: + + Schema::table('users', function (Blueprint $table) { + $table->string('email'); + }); + +#### Available Column Types + +Of course, the schema builder contains a variety of column types that you may specify when building your tables: + +Command | Description +------------- | ------------- +`$table->bigIncrements('id');` | Incrementing ID (primary key) using a "UNSIGNED BIG INTEGER" equivalent. +`$table->bigInteger('votes');` | BIGINT equivalent for the database. +`$table->binary('data');` | BLOB equivalent for the database. +`$table->boolean('confirmed');` | BOOLEAN equivalent for the database. +`$table->char('name', 4);` | CHAR equivalent with a length. +`$table->date('created_at');` | DATE equivalent for the database. +`$table->dateTime('created_at');` | DATETIME equivalent for the database. +`$table->dateTimeTz('created_at');` | DATETIME (with timezone) equivalent for the database. +`$table->decimal('amount', 5, 2);` | DECIMAL equivalent with a precision and scale. +`$table->double('column', 15, 8);` | DOUBLE equivalent with precision, 15 digits in total and 8 after the decimal point. +`$table->enum('choices', ['foo', 'bar']);` | ENUM equivalent for the database. +`$table->float('amount', 8, 2);` | FLOAT equivalent for the database, 8 digits in total and 2 after the decimal point. +`$table->increments('id');` | Incrementing ID (primary key) using a "UNSIGNED INTEGER" equivalent. +`$table->integer('votes');` | INTEGER equivalent for the database. +`$table->ipAddress('visitor');` | IP address equivalent for the database. +`$table->json('options');` | JSON equivalent for the database. +`$table->jsonb('options');` | JSONB equivalent for the database. +`$table->longText('description');` | LONGTEXT equivalent for the database. +`$table->macAddress('device');` | MAC address equivalent for the database. +`$table->mediumIncrements('id');` | Incrementing ID (primary key) using a "UNSIGNED MEDIUM INTEGER" equivalent. +`$table->mediumInteger('numbers');` | MEDIUMINT equivalent for the database. +`$table->mediumText('description');` | MEDIUMTEXT equivalent for the database. +`$table->morphs('taggable');` | Adds unsigned INTEGER `taggable_id` and STRING `taggable_type`. +`$table->nullableMorphs('taggable');` | Nullable versions of the `morphs()` columns. +`$table->nullableTimestamps();` | Nullable versions of the `timestamps()` columns. +`$table->rememberToken();` | Adds `remember_token` as VARCHAR(100) NULL. +`$table->smallIncrements('id');` | Incrementing ID (primary key) using a "UNSIGNED SMALL INTEGER" equivalent. +`$table->smallInteger('votes');` | SMALLINT equivalent for the database. +`$table->softDeletes();` | Adds nullable `deleted_at` column for soft deletes. +`$table->string('email');` | VARCHAR equivalent column. +`$table->string('name', 100);` | VARCHAR equivalent with a length. +`$table->text('description');` | TEXT equivalent for the database. +`$table->time('sunrise');` | TIME equivalent for the database. +`$table->timeTz('sunrise');` | TIME (with timezone) equivalent for the database. +`$table->tinyInteger('numbers');` | TINYINT equivalent for the database. +`$table->timestamp('added_on');` | TIMESTAMP equivalent for the database. +`$table->timestampTz('added_on');` | TIMESTAMP (with timezone) equivalent for the database. +`$table->timestamps();` | Adds nullable `created_at` and `updated_at` columns. +`$table->timestampsTz();` | Adds nullable `created_at` and `updated_at` (with timezone) columns. +`$table->unsignedBigInteger('votes');` | Unsigned BIGINT equivalent for the database. +`$table->unsignedInteger('votes');` | Unsigned INT equivalent for the database. +`$table->unsignedMediumInteger('votes');` | Unsigned MEDIUMINT equivalent for the database. +`$table->unsignedSmallInteger('votes');` | Unsigned SMALLINT equivalent for the database. +`$table->unsignedTinyInteger('votes');` | Unsigned TINYINT equivalent for the database. +`$table->uuid('id');` | UUID equivalent for the database. + + +### Column Modifiers + +In addition to the column types listed above, there are several column "modifiers" you may use while adding a column to a database table. For example, to make the column "nullable", you may use the `nullable` method: + + Schema::table('users', function (Blueprint $table) { + $table->string('email')->nullable(); + }); + +Below is a list of all the available column modifiers. This list does not include the [index modifiers](#creating-indexes): + +Modifier | Description +------------- | ------------- +`->after('column')` | Place the column "after" another column (MySQL Only) +`->comment('my comment')` | Add a comment to a column +`->default($value)` | Specify a "default" value for the column +`->first()` | Place the column "first" in the table (MySQL Only) +`->nullable()` | Allow NULL values to be inserted into the column +`->storedAs($expression)` | Create a stored generated column (MySQL Only) +`->unsigned()` | Set `integer` columns to `UNSIGNED` +`->virtualAs($expression)` | Create a virtual generated column (MySQL Only) + + + +### Modifying Columns + +#### Prerequisites + +Before modifying a column, be sure to add the `doctrine/dbal` dependency to your `composer.json` file. The Doctrine DBAL library is used to determine the current state of the column and create the SQL queries needed to make the specified adjustments to the column: + + composer require doctrine/dbal + +#### Updating Column Attributes + +The `change` method allows you to modify some existing column types to a new type or modify the column's attributes. For example, you may wish to increase the size of a string column. To see the `change` method in action, let's increase the size of the `name` column from 25 to 50: + + Schema::table('users', function (Blueprint $table) { + $table->string('name', 50)->change(); + }); + +We could also modify a column to be nullable: + + Schema::table('users', function (Blueprint $table) { + $table->string('name', 50)->nullable()->change(); + }); + +> {note} The following column types can not be "changed": char, double, enum, mediumInteger, timestamp, tinyInteger, ipAddress, json, jsonb, macAddress, mediumIncrements, morphs, nullableMorphs, nullableTimestamps, softDeletes, timeTz, timestampTz, timestamps, timestampsTz, unsignedMediumInteger, unsignedTinyInteger, uuid. + + +#### Renaming Columns + +To rename a column, you may use the `renameColumn` method on the Schema builder. Before renaming a column, be sure to add the `doctrine/dbal` dependency to your `composer.json` file: + + Schema::table('users', function (Blueprint $table) { + $table->renameColumn('from', 'to'); + }); + +> {note} Renaming any column in a table that also has a column of type `enum` is not currently supported. + + +### Dropping Columns + +To drop a column, use the `dropColumn` method on the Schema builder. Before dropping columns from a SQLite database, you will need to add the `doctrine/dbal` dependency to your `composer.json` file and run the `composer update` command in your terminal to install the library: + + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('votes'); + }); + +You may drop multiple columns from a table by passing an array of column names to the `dropColumn` method: + + Schema::table('users', function (Blueprint $table) { + $table->dropColumn(['votes', 'avatar', 'location']); + }); + +> {note} Dropping or modifying multiple columns within a single migration while using a SQLite database is not supported. + + +## Indexes + + +### Creating Indexes + +The schema builder supports several types of indexes. First, let's look at an example that specifies a column's values should be unique. To create the index, we can simply chain the `unique` method onto the column definition: + + $table->string('email')->unique(); + +Alternatively, you may create the index after defining the column. For example: + + $table->unique('email'); + +You may even pass an array of columns to an index method to create a compound index: + + $table->index(['account_id', 'created_at']); + +Laravel will automatically generate a reasonable index name, but you may pass a second argument to the method to specify the name yourself: + + $table->index('email', 'my_index_name'); + +#### Available Index Types -#### Migrations နောက်ပြန်ခြင်း +Command | Description +------------- | ------------- +`$table->primary('id');` | Add a primary key. +`$table->primary(['first', 'last']);` | Add composite keys. +`$table->unique('email');` | Add a unique index. +`$table->unique('state', 'my_index_name');` | Add a custom index name. +`$table->unique(['first', 'last']);` | Add a composite unique index. +`$table->index('state');` | Add a basic index. - php artisan migrate:rollback +#### Index Lengths & MySQL / MariaDB -#### Migrations ပထမဆုံး အခြေအနေသို ့ နောက်ပြန်ခြင်း +Laravel uses the `utf8mb4` character set by default, which includes support for storing "emojis" in the database. If you are running a version of MySQL older than the 5.7.7 release or MariaDB older than the 10.2.2 release, you may need to manually configure the default string length generated by migrations in order for MySQL to create indexes for them. You may configure this by calling the `Schema::defaultStringLength` method within your `AppServiceProvider`: - php artisan migrate:reset + use Illuminate\Support\Facades\Schema; -#### အစမှ အဆုံး နောက်ပြန်ပြီးနောက် တဖန် Migration ပြုလုပ်ခြင်း + /** + * Bootstrap any application services. + * + * @return void + */ + public function boot() + { + Schema::defaultStringLength(191); + } - php artisan migrate:refresh +Alternatively, you may enable the `innodb_large_prefix` option for your database. Refer to your database's documentation for instructions on how to properly enable this option. - php artisan migrate:refresh --seed + +### Dropping Indexes - -## Database Seeding +To drop an index, you must specify the index's name. By default, Laravel automatically assigns a reasonable name to the indexes. Simply concatenate the table name, the name of the indexed column, and the index type. Here are some examples: -Laravel အနေဖြင့် database ကို အလွယ်တကူ seed ပြုလုပ်နိုင်ရင် seed classes များပါရှိပါသည်။ Seed class များမှာ `app/database/seeds` တွင်တည်ရှိမည် ဖြစ်သည်။ Seed class များကို အလိုရှိသလို အမည်ပေးနိုင်သော်လည်း အဓိပ္ပါယ်ရှိသော နာမည်မျိုး ဥပမာ `UserTableSeeder` စသဖြင့်သာ ပေးသင့်သည်။ ပုံမှန်အားဖြင့် `DatabaseSeeder` class မှာ ဖန်တီးပေးထားသည်။ ထို class မှ သင့်အနေဖြင့် `call` method ကို အသုံးပြုကာ -အစီအစဉ်အလိုက် အခြားသော seed classes များကို run နိုင်သည်။ +Command | Description +------------- | ------------- +`$table->dropPrimary('users_id_primary');` | Drop a primary key from the "users" table. +`$table->dropUnique('users_email_unique');` | Drop a unique index from the "users" table. +`$table->dropIndex('geo_state_index');` | Drop a basic index from the "geo" table. -#### Example Database Seed Class +If you pass an array of columns into a method that drops indexes, the conventional index name will be generated based on the table name, columns and key type: - class DatabaseSeeder extends Seeder { + Schema::table('geo', function (Blueprint $table) { + $table->dropIndex(['state']); // Drops index 'geo_state_index' + }); - public function run() - { - $this->call('UserTableSeeder'); + +### Foreign Key Constraints - $this->command->info('User table seeded!'); - } +Laravel also provides support for creating foreign key constraints, which are used to force referential integrity at the database level. For example, let's define a `user_id` column on the `posts` table that references the `id` column on a `users` table: - } + Schema::table('posts', function (Blueprint $table) { + $table->integer('user_id')->unsigned(); - class UserTableSeeder extends Seeder { + $table->foreign('user_id')->references('id')->on('users'); + }); - public function run() - { - DB::table('users')->delete(); +You may also specify the desired action for the "on delete" and "on update" properties of the constraint: - User::create(array('email' => 'foo@bar.com')); - } + $table->foreign('user_id') + ->references('id')->on('users') + ->onDelete('cascade'); - } +To drop a foreign key, you may use the `dropForeign` method. Foreign key constraints use the same naming convention as indexes. So, we will concatenate the table name and the columns in the constraint then suffix the name with "_foreign": -Database ကို seed ပြုလုပ်ရန် Artisan CLI မှ `db:seed` command ကို အသုံးပြုနိုင်သည်။ + $table->dropForeign('posts_user_id_foreign'); - php artisan db:seed +Or, you may pass an array value which will automatically use the conventional constraint name when dropping: -ပုံမှန်အားဖြင့် `db:seed` command မှာ `DatabaseSeeder` class ကို run မည်ဖြစ်ပြီး ထိုမှတဆင့် အခြား seed class များကို ခေါ်ယူမည် ဖြစ်သည်။ သို ့ပင်သော်ညား `--class` option ကို အသုံးပြုကာ သီးသန် ့ seeder class တစ်ခုချင်းစီလည်း run နိုင်ပါသေးသည်။ + $table->dropForeign(['user_id']); - php artisan db:seed --class=UserTableSeeder +You may enable or disable foreign key constraints within your migrations by using the following methods: -ထိုအပြင် `migrate:refresh` ကိုအသုံးပြုကာ, rollback ပြုလုပ်ပြီး migrations ကို အစမှ တဖန်ပြန်၍ run ခြင်းကိုလည်း ပြုလုပ်နိုင်မည် ဖြစ်သည်။ + Schema::enableForeignKeyConstraints(); - php artisan migrate:refresh --seed + Schema::disableForeignKeyConstraints(); diff --git a/mix.md b/mix.md new file mode 100644 index 0000000..d05d29e --- /dev/null +++ b/mix.md @@ -0,0 +1,209 @@ +# Compiling Assets (Laravel Mix) + +- [Introduction](#introduction) +- [Installation & Setup](#installation) +- [Running Mix](#running-mix) +- [Working With Stylesheets](#working-with-stylesheets) + - [Less](#less) + - [Sass](#sass) + - [Plain CSS](#plain-css) + - [Source Maps](#css-source-maps) +- [Working With JavaScript](#working-with-scripts) + - [Code Splitting](#code-splitting) + - [Custom Webpack Configuration](#custom-webpack-configuration) +- [Copying Files & Directories](#copying-files-and-directories) +- [Versioning / Cache Busting](#versioning-and-cache-busting) +- [Notifications](#notifications) + + +## Introduction + +Laravel Mix provides a fluent API for defining Webpack build steps for your Laravel application using several common CSS and JavaScript pre-processors. Through simple method chaining, you can fluently define your asset pipeline. For example: + + mix.js('resources/assets/js/app.js', 'public/js') + .sass('resources/assets/sass/app.scss', 'public/css'); + +If you've ever been confused and overwhelmed about getting started with Webpack and asset compilation, you will love Laravel Mix. However, you are not required to use it while developing your application. Of course, you are free to use any asset pipeline tool you wish, or even none at all. + + +## Installation & Setup + +#### Installing Node + +Before triggering Mix, you must first ensure that Node.js and NPM are installed on your machine. + + node -v + npm -v + +By default, Laravel Homestead includes everything you need; however, if you aren't using Vagrant, then you can easily install the latest version of Node and NPM using simple graphical installers from [their download page](https://nodejs.org/en/download/). + +#### Laravel Mix + +The only remaining step is to install Laravel Mix. Within a fresh installation of Laravel, you'll find a `package.json` file in the root of your directory structure. The default `package.json` file includes everything you need to get started. Think of this like your `composer.json` file, except it defines Node dependencies instead of PHP. You may install the dependencies it references by running: + + npm install + +If you are developing on a Windows system or you are running your VM on a Windows host system, you may need to run the `npm install` command with the `--no-bin-links` switch enabled: + + npm install --no-bin-links + + +## Running Mix + +Mix is a configuration layer on top of [Webpack](https://webpack.js.org), so to run your Mix tasks you only need to execute one of the NPM scripts that is included with the default Laravel `package.json` file: + + // Run all Mix tasks... + npm run dev + + // Run all Mix tasks and minify output... + npm run production + +#### Watching Assets For Changes + +The `npm run watch` command will continue running in your terminal and watch all relevant files for changes. Webpack will then automatically recompile your assets when it detects a change: + + npm run watch + + +## Working With Stylesheets + +The `webpack.mix.js` file is your entry point for all asset compilation. Think of it as a light configuration wrapper around Webpack. Mix tasks can be chained together to define exactly how your assets should be compiled. + + +### Less + +The `less` method may be used to compile [Less](http://lesscss.org/) into CSS. Let's compile our primary `app.less` file to `public/css/app.css`. + + mix.less('resources/assets/less/app.less', 'public/css'); + +Multiple calls to the `less` method may be used to compile multiple files: + + mix.less('resources/assets/less/app.less', 'public/css') + .less('resources/assets/less/admin.less', 'public/css'); + +If you wish to customize the file name of the compiled CSS, you may pass a full file path as the second argument to the `less` method: + + mix.less('resources/assets/less/app.less', 'public/stylesheets/styles.css'); + + +### Sass + +The `sass` method allows you to compile [Sass](http://sass-lang.com/) into CSS. You may use the method like so: + + mix.sass('resources/assets/sass/app.scss', 'public/css'); + +Again, like the `less` method, you may compile multiple Sass files into their own respective CSS files and even customize the output directory of the resulting CSS: + + mix.sass('resources/assets/sass/app.sass', 'public/css') + .sass('resources/assets/sass/admin.sass', 'public/css/admin'); + + +### Plain CSS + +If you would just like to combine some plain CSS stylesheets into a single file, you may use the `combine` method. This method also supports concatenating JavaScript files: + + mix.combine([ + 'public/css/vendor/normalize.css', + 'public/css/vendor/videojs.css' + ], 'public/css/all.css'); + + +### Source Maps + +Though disabled by default, source maps may be activated by calling the `mix.sourceMaps()` method in your `webpack.mix.js` file. Though it comes with a compile/performance cost, this will provide extra debugging information to your browser's developer tools when using compiled assets. + + mix.js('resources/assets/js/app.js', 'public/js') + .sourceMaps(); + + +## Working With JavaScript + +Mix provides several features to help you work with your JavaScript files, such as compiling ECMAScript 2015, module bundling, minification, and simply concatenating plain JavaScript files. Even better, this all works seamlessly, without requiring an ounce of custom configuration: + + mix.js('resources/assets/js/app.js', 'public/js'); + +With this single line of code, you may now take advantage of: + +
    +- ES2015 syntax. +- Compilation of `.vue` files. +- Minification for production environments. +
    + + +### Code Splitting + +One potential downside to bundling all application-specific JavaScript with your vendor libraries is that it makes long-term caching more difficult. For example, a single update to your application code will force the browser to re-download all of your vendor libraries even if they haven't changed. + +If you intend to make frequent updates to your application's JavaScript, you should consider extracting all of your vendor libraries into their file. This way, a change to your application code will not affect the caching of your large `vendor.js` file. Mix's `extract` method makes this a breeze: + + mix.js('resources/assets/js/app.js', 'public/js') + .extract(['vue']) + +The `extract` method accepts an array of all libraries or modules that you wish to extract into a `vendor.js` file. Using the above snippet as an example, Mix will generate the following files: + +
    +- `public/js/manifest.js`: *The Webpack manifest runtime* +- `public/js/vendor.js`: *Your vendor libraries* +- `public/js/app.js`: *Your application code* +
    + +To avoid JavaScript errors, be sure to load these files in the proper order: + + + + + + +### Custom Webpack Configuration + +Behind the scenes, Laravel Mix references a pre-configured `webpack.config.js` file to get you up and running as quickly as possible. Occasionally, you may need to manually modify this file. You might have a special loader or plugin that needs to be referenced, or maybe you prefer to use Stylus instead of Sass. In such instances, you have two choices: + +#### Merging + +Mix provides a useful `webpackConfig` method that allows you to merge any short Webpack configuration overrides. This is a particularly appealing choice, as it doesn't require you to copy and maintain your own copy of the `webpack.config.js` file. The `webpackConfig` method accepts an object, which should contain any [Webpack-specific configuration](https://webpack.js.org/configuration/) that you wish to apply. + + mix.webpackConfig({ + resolve: { + modules: [ + path.resolve(__dirname, 'vendor/laravel/spark/resources/assets/js') + ] + } + }); + +#### Reference Your Own Configuration + +A second option is to copy Mix's `webpack.config.js` into your project root. + + cp node_modules/laravel-mix/setup/webpack.config.js ./ + +Next, you'll need to update the NPM scripts in your `package.json` to ensure that they no longer reference Mix's configuration file directly. Simply remove the `--config="node_modules/laravel-mix/setup/webpack.config.js"` entry from the commands. Once this has been done, you may freely modify your configuration file as needed. + + + +## Copying Files & Directories + +The `copy` method may be used to copy files and directories to new locations. This can be useful when a particular asset within your `node_modules` directory needs to be relocated to your `public` folder. + + mix.copy('node_modules/foo/bar.css', 'public/css/bar.css'); + + +## Versioning / Cache Busting + +Many developers suffix their compiled assets with a timestamp or unique token to force browsers to load the fresh assets instead of serving stale copies of the code. Mix can handle this for you using the `version` method. + +When executed in a production environment (`npm run production`), the `version` method will automatically append a unique hash to the filenames of all compiled files, allowing for more convenient cache busting: + + mix.js('resources/assets/js/app.js', 'public/js') + .version(); + +After generating the versioned file, you won't know the exact file name. So, you should use Laravel's global `mix` function within your [views](/docs/{{version}}/views) to load the appropriately hashed asset. The `mix` function will automatically determine the current name of the hashed file: + + + + +## Notifications + +When available, Mix will automatically display OS notifications for each bundle. This will give you instant feedback, as to whether the compilation was successful or not. However, there may be instances when you'd prefer to disable these notifications. One such example might be triggering Mix on your production server. Notifications may be deactivated, via the `disableNotifications` method. + + mix.disableNotifications(); diff --git a/mocking.md b/mocking.md new file mode 100644 index 0000000..95a7e13 --- /dev/null +++ b/mocking.md @@ -0,0 +1,260 @@ +# Mocking + +- [Introduction](#introduction) +- [Bus Fake](#bus-fake) +- [Event Fake](#event-fake) +- [Mail Fake](#mail-fake) +- [Notification Fake](#notification-fake) +- [Queue Fake](#queue-fake) +- [Facades](#mocking-facades) + + +## Introduction + +When testing Laravel applications, you may wish to "mock" certain aspects of your application so they are not actually executed during a given test. For example, when testing a controller that dispatches an event, you may wish to mock the event listeners so they are not actually executed during the test. This allows you to only test the controller's HTTP response without worrying about the execution of the event listeners, since the event listeners can be tested in their own test case. + +Laravel provides helpers for mocking events, jobs, and facades out of the box. These helpers primarily provide a convenience layer over Mockery so you do not have to manually make complicated Mockery method calls. Of course, you are free to use [Mockery](http://docs.mockery.io/en/latest/) or PHPUnit to create your own mocks or spies. + + +## Bus Fake + +As an alternative to mocking, you may use the `Bus` facade's `fake` method to prevent jobs from being dispatched. When using fakes, assertions are made after the code under test is executed: + + order->id === $order->id; + }); + + // Assert a job was not dispatched... + Bus::assertNotDispatched(AnotherJob::class); + } + } + + +## Event Fake + +As an alternative to mocking, you may use the `Event` facade's `fake` method to prevent all event listeners from executing. You may then assert that events were dispatched and even inspect the data they received. When using fakes, assertions are made after the code under test is executed: + + order->id === $order->id; + }); + + Event::assertNotDispatched(OrderFailedToShip::class); + } + } + + +## Mail Fake + +You may use the `Mail` facade's `fake` method to prevent mail from being sent. You may then assert that [mailables](/docs/{{version}}/mail) were sent to users and even inspect the data they received. When using fakes, assertions are made after the code under test is executed: + + order->id === $order->id; + }); + + // Assert a message was sent to the given users... + Mail::assertSent(OrderShipped::class, function ($mail) use ($user) { + return $mail->hasTo($user->email) && + $mail->hasCc('...') && + $mail->hasBcc('...'); + }); + + // Assert a mailable was not sent... + Mail::assertNotSent(AnotherMailable::class); + } + } + + +## Notification Fake + +You may use the `Notification` facade's `fake` method to prevent notifications from being sent. You may then assert that [notifications](/docs/{{version}}/notifications) were sent to users and even inspect the data they received. When using fakes, assertions are made after the code under test is executed: + + order->id === $order->id; + } + ); + + // Assert a notification was sent to the given users... + Notification::assertSentTo( + [$user], OrderShipped::class + ); + + // Assert a notification was not sent... + Notification::assertNotSentTo( + [$user], AnotherNotification::class + ); + } + } + + +## Queue Fake + +As an alternative to mocking, you may use the `Queue` facade's `fake` method to prevent jobs from being queued. You may then assert that jobs were pushed to the queue and even inspect the data they received. When using fakes, assertions are made after the code under test is executed: + + order->id === $order->id; + }); + + // Assert a job was pushed to a given queue... + Queue::assertPushedOn('queue-name', ShipOrder::class); + + // Assert a job was not pushed... + Queue::assertNotPushed(AnotherJob::class); + } + } + + +## Facades + +Unlike traditional static method calls, [facades](/docs/{{version}}/facades) may be mocked. This provides a great advantage over traditional static methods and grants you the same testability you would have if you were using dependency injection. When testing, you may often want to mock a call to a Laravel facade in one of your controllers. For example, consider the following controller action: + + once() + ->with('key') + ->andReturn('value'); + + $response = $this->get('/users'); + + // ... + } + } + +> {note} You should not mock the `Request` facade. Instead, pass the input you desire into the HTTP helper methods such as `get` and `post` when running your test. Likewise, instead of mocking the `Config` facade, simply call the `Config::set` method in your tests. diff --git a/notifications.md b/notifications.md new file mode 100644 index 0000000..7848f04 --- /dev/null +++ b/notifications.md @@ -0,0 +1,851 @@ +# Notifications + +- [Introduction](#introduction) +- [Creating Notifications](#creating-notifications) +- [Sending Notifications](#sending-notifications) + - [Using The Notifiable Trait](#using-the-notifiable-trait) + - [Using The Notification Facade](#using-the-notification-facade) + - [Specifying Delivery Channels](#specifying-delivery-channels) + - [Queueing Notifications](#queueing-notifications) +- [Mail Notifications](#mail-notifications) + - [Formatting Mail Messages](#formatting-mail-messages) + - [Customizing The Recipient](#customizing-the-recipient) + - [Customizing The Subject](#customizing-the-subject) + - [Customizing The Templates](#customizing-the-templates) +- [Markdown Mail Notifications](#markdown-mail-notifications) + - [Generating The Message](#generating-the-message) + - [Writing The Message](#writing-the-message) + - [Customizing The Components](#customizing-the-components) +- [Database Notifications](#database-notifications) + - [Prerequisites](#database-prerequisites) + - [Formatting Database Notifications](#formatting-database-notifications) + - [Accessing The Notifications](#accessing-the-notifications) + - [Marking Notifications As Read](#marking-notifications-as-read) +- [Broadcast Notifications](#broadcast-notifications) + - [Prerequisites](#broadcast-prerequisites) + - [Formatting Broadcast Notifications](#formatting-broadcast-notifications) + - [Listening For Notifications](#listening-for-notifications) +- [SMS Notifications](#sms-notifications) + - [Prerequisites](#sms-prerequisites) + - [Formatting SMS Notifications](#formatting-sms-notifications) + - [Customizing The "From" Number](#customizing-the-from-number) + - [Routing SMS Notifications](#routing-sms-notifications) +- [Slack Notifications](#slack-notifications) + - [Prerequisites](#slack-prerequisites) + - [Formatting Slack Notifications](#formatting-slack-notifications) + - [Slack Attachments](#slack-attachments) + - [Routing Slack Notifications](#routing-slack-notifications) +- [Notification Events](#notification-events) +- [Custom Channels](#custom-channels) + + +## Introduction + +In addition to support for [sending email](/docs/{{version}}/mail), Laravel provides support for sending notifications across a variety of delivery channels, including mail, SMS (via [Nexmo](https://www.nexmo.com/)), and [Slack](https://slack.com). Notifications may also be stored in a database so they may be displayed in your web interface. + +Typically, notifications should be short, informational messages that notify users of something that occurred in your application. For example, if you are writing a billing application, you might send an "Invoice Paid" notification to your users via the email and SMS channels. + + +## Creating Notifications + +In Laravel, each notification is represented by a single class (typically stored in the `app/Notifications` directory). Don't worry if you don't see this directory in your application, it will be created for you when you run the `make:notification` Artisan command: + + php artisan make:notification InvoicePaid + +This command will place a fresh notification class in your `app/Notifications` directory. Each notification class contains a `via` method and a variable number of message building methods (such as `toMail` or `toDatabase`) that convert the notification to a message optimized for that particular channel. + + +## Sending Notifications + + +### Using The Notifiable Trait + +Notifications may be sent in two ways: using the `notify` method of the `Notifiable` trait or using the `Notification` [facade](/docs/{{version}}/facades). First, let's explore using the trait: + + notify(new InvoicePaid($invoice)); + +> {tip} Remember, you may use the `Illuminate\Notifications\Notifiable` trait on any of your models. You are not limited to only including it on your `User` model. + + +### Using The Notification Facade + +Alternatively, you may send notifications via the `Notification` [facade](/docs/{{version}}/facades). This is useful primarily when you need to send a notification to multiple notifiable entities such as a collection of users. To send notifications using the facade, pass all of the notifiable entities and the notification instance to the `send` method: + + Notification::send($users, new InvoicePaid($invoice)); + + +### Specifying Delivery Channels + +Every notification class has a `via` method that determines on which channels the notification will be delivered. Out of the box, notifications may be sent on the `mail`, `database`, `broadcast`, `nexmo`, and `slack` channels. + +> {tip} If you would like to use other delivery channels such as Telegram or Pusher, check out the community driven [Laravel Notification Channels website](http://laravel-notification-channels.com). + +The `via` method receives a `$notifiable` instance, which will be an instance of the class to which the notification is being sent. You may use `$notifiable` to determine which channels the notification should be delivered on: + + /** + * Get the notification's delivery channels. + * + * @param mixed $notifiable + * @return array + */ + public function via($notifiable) + { + return $notifiable->prefers_sms ? ['nexmo'] : ['mail', 'database']; + } + + +### Queueing Notifications + +> {note} Before queueing notifications you should configure your queue and [start a worker](/docs/{{version}}/queues). + +Sending notifications can take time, especially if the channel needs an external API call to deliver the notification. To speed up your application's response time, let your notification be queued by adding the `ShouldQueue` interface and `Queueable` trait to your class. The interface and trait are already imported for all notifications generated using `make:notification`, so you may immediately add them to your notification class: + + notify(new InvoicePaid($invoice)); + +If you would like to delay the delivery of the notification, you may chain the `delay` method onto your notification instantiation: + + $when = Carbon::now()->addMinutes(10); + + $user->notify((new InvoicePaid($invoice))->delay($when)); + + +## Mail Notifications + + +### Formatting Mail Messages + +If a notification supports being sent as an email, you should define a `toMail` method on the notification class. This method will receive a `$notifiable` entity and should return a `Illuminate\Notifications\Messages\MailMessage` instance. Mail messages may contain lines of text as well as a "call to action". Let's take a look at an example `toMail` method: + + /** + * Get the mail representation of the notification. + * + * @param mixed $notifiable + * @return \Illuminate\Notifications\Messages\MailMessage + */ + public function toMail($notifiable) + { + $url = url('/invoice/'.$this->invoice->id); + + return (new MailMessage) + ->greeting('Hello!') + ->line('One of your invoices has been paid!') + ->action('View Invoice', $url) + ->line('Thank you for using our application!'); + } + +> {tip} Note we are using `$this->invoice->id` in our `message` method. You may pass any data your notification needs to generate its message into the notification's constructor. + +In this example, we register a greeting, a line of text, a call to action, and then another line of text. These methods provided by the `MailMessage` object make it simple and fast to format small transactional emails. The mail channel will then translate the message components into a nice, responsive HTML email template with a plain-text counterpart. Here is an example of an email generated by the `mail` channel: + + + +> {tip} When sending mail notifications, be sure to set the `name` value in your `config/app.php` configuration file. This value will be used in the header and footer of your mail notification messages. + + +#### Error Messages + +Some notifications inform users of errors, such as a failed invoice payment. You may indicate that a mail message is regarding an error by calling the `error` method when building your message. When using the `error` method on a mail message, the call to action button will be red instead of blue: + + /** + * Get the mail representation of the notification. + * + * @param mixed $notifiable + * @return \Illuminate\Notifications\Message + */ + public function toMail($notifiable) + { + return (new MailMessage) + ->error() + ->subject('Notification Subject') + ->line('...'); + } + + +### Customizing The Recipient + +When sending notifications via the `mail` channel, the notification system will automatically look for an `email` property on your notifiable entity. You may customize which email address is used to deliver the notification by defining a `routeNotificationForMail` method on the entity: + + email_address; + } + } + + +### Customizing The Subject + +By default, the email's subject is the class name of the notification formatted to "title case". So, if your notification class is named `InvoicePaid`, the email's subject will be `Invoice Paid`. If you would like to specify an explicit subject for the message, you may call the `subject` method when building your message: + + /** + * Get the mail representation of the notification. + * + * @param mixed $notifiable + * @return \Illuminate\Notifications\Messages\MailMessage + */ + public function toMail($notifiable) + { + return (new MailMessage) + ->subject('Notification Subject') + ->line('...'); + } + + +### Customizing The Templates + +You can modify the HTML and plain-text template used by mail notifications by publishing the notification package's resources. After running this command, the mail notification templates will be located in the `resources/views/vendor/notifications` directory: + + php artisan vendor:publish --tag=laravel-notifications + + +## Markdown Mail Notifications + +Markdown mail notifications allow you to take advantage of the pre-built templates of mail notifications, while giving you more freedom to write longer, customized messages. Since the messages are written in Markdown, Laravel is able to render beautiful, responsive HTML templates for the messages while also automatically generating a plain-text counterpart. + + +### Generating The Message + +To generate a notification with a corresponding Markdown template, you may use the `--markdown` option of the `make:notification` Artisan command: + + php artisan make:notification InvoicePaid --markdown=mail.invoice.paid + +Like all other mail notifications, notifications that use Markdown templates should define a `toMail` method on their notification class. However, instead of using the `line` and `action` methods to construct the notification, use the `markdown` method to specify the name of the Markdown template that should be used: + + /** + * Get the mail representation of the notification. + * + * @param mixed $notifiable + * @return \Illuminate\Notifications\Messages\MailMessage + */ + public function toMail($notifiable) + { + $url = url('/invoice/'.$this->invoice->id); + + return (new MailMessage) + ->subject('Invoice Paid') + ->markdown('mail.invoice.paid', ['url' => $url]); + } + + +### Writing The Message + +Markdown mail notifications use a combination of Blade components and Markdown syntax which allow you to easily construct notifications while leveraging Laravel's pre-crafted notification components: + + @component('mail::message') + # Invoice Paid + + Your invoice has been paid! + + @component('mail::button', ['url' => $url]) + View Invoice + @endcomponent + + Thanks,
    + {{ config('app.name') }} + @endcomponent + +#### Button Component + +The button component renders a centered button link. The component accepts two arguments, a `url` and an optional `color`. Supported colors are `blue`, `green`, and `red`. You may add as many button components to a notification as you wish: + + @component('mail::button', ['url' => $url, 'color' => 'green']) + View Invoice + @endcomponent + +#### Panel Component + +The panel component renders the given block of text in a panel that has a slightly different background color than the rest of the notification. This allows you to draw attention to a given block of text: + + @component('mail::panel') + This is the panel content. + @endcomponent + +#### Table Component + +The table component allows you to transform a Markdown table into an HTML table. The component accepts the Markdown table as its content. Table column alignment is supported using the default Markdown table alignment syntax: + + @component('mail::table') + | Laravel | Table | Example | + | ------------- |:-------------:| --------:| + | Col 2 is | Centered | $10 | + | Col 3 is | Right-Aligned | $20 | + @endcomponent + + +### Customizing The Components + +You may export all of the Markdown notification components to your own application for customization. To export the components, use the `vendor:publish` Artisan command to publish the `laravel-mail` asset tag: + + php artisan vendor:publish --tag=laravel-mail + +This command will publish the Markdown mail components to the `resources/views/vendor/mail` directory. The `mail` directory will contain a `html` and a `markdown` directory, each containing their respective representations of every available component. You are free to customize these components however you like. + +#### Customizing The CSS + +After exporting the components, the `resources/views/vendor/mail/html/themes` directory will contain a `default.css` file. You may customize the CSS in this file and your styles will automatically be in-lined within the HTML representations of your Markdown notifications. + +> {tip} If you would like to build an entirely new theme for the Markdown components, simply write a new CSS file within the `html/themes` directory and change the `theme` option of your `mail` configuration file. + + +## Database Notifications + + +### Prerequisites + +The `database` notification channel stores the notification information in a database table. This table will contain information such as the notification type as well as custom JSON data that describes the notification. + +You can query the table to display the notifications in your application's user interface. But, before you can do that, you will need to create a database table to hold your notifications. You may use the `notifications:table` command to generate a migration with the proper table schema: + + php artisan notifications:table + + php artisan migrate + + +### Formatting Database Notifications + +If a notification supports being stored in a database table, you should define a `toDatabase` or `toArray` method on the notification class. This method will receive a `$notifiable` entity and should return a plain PHP array. The returned array will be encoded as JSON and stored in the `data` column of your `notifications` table. Let's take a look at an example `toArray` method: + + /** + * Get the array representation of the notification. + * + * @param mixed $notifiable + * @return array + */ + public function toArray($notifiable) + { + return [ + 'invoice_id' => $this->invoice->id, + 'amount' => $this->invoice->amount, + ]; + } + +#### `toDatabase` Vs. `toArray` + +The `toArray` method is also used by the `broadcast` channel to determine which data to broadcast to your JavaScript client. If you would like to have two different array representations for the `database` and `broadcast` channels, you should define a `toDatabase` method instead of a `toArray` method. + + +### Accessing The Notifications + +Once notifications are stored in the database, you need a convenient way to access them from your notifiable entities. The `Illuminate\Notifications\Notifiable` trait, which is included on Laravel's default `App\User` model, includes a `notifications` Eloquent relationship that returns the notifications for the entity. To fetch notifications, you may access this method like any other Eloquent relationship. By default, notifications will be sorted by the `created_at` timestamp: + + $user = App\User::find(1); + + foreach ($user->notifications as $notification) { + echo $notification->type; + } + +If you want to retrieve only the "unread" notifications, you may use the `unreadNotifications` relationship. Again, these notifications will be sorted by the `created_at` timestamp: + + $user = App\User::find(1); + + foreach ($user->unreadNotifications as $notification) { + echo $notification->type; + } + +> {tip} To access your notifications from your JavaScript client, you should define a notification controller for your application which returns the notifications for a notifiable entity, such as the current user. You may then make an HTTP request to that controller's URI from your JavaScript client. + + +### Marking Notifications As Read + +Typically, you will want to mark a notification as "read" when a user views it. The `Illuminate\Notifications\Notifiable` trait provides a `markAsRead` method, which updates the `read_at` column on the notification's database record: + + $user = App\User::find(1); + + foreach ($user->unreadNotifications as $notification) { + $notification->markAsRead(); + } + +However, instead of looping through each notification, you may use the `markAsRead` method directly on a collection of notifications: + + $user->unreadNotifications->markAsRead(); + +You may also use a mass-update query to mark all of the notifications as read without retrieving them from the database: + + $user = App\User::find(1); + + $user->unreadNotifications()->update(['read_at' => Carbon::now()]); + +Of course, you may `delete` the notifications to remove them from the table entirely: + + $user->notifications()->delete(); + + +## Broadcast Notifications + + +### Prerequisites + +Before broadcasting notifications, you should configure and be familiar with Laravel's [event broadcasting](/docs/{{version}}/broadcasting) services. Event broadcasting provides a way to react to server-side fired Laravel events from your JavaScript client. + + +### Formatting Broadcast Notifications + +The `broadcast` channel broadcasts notifications using Laravel's [event broadcasting](/docs/{{version}}/broadcasting) services, allowing your JavaScript client to catch notifications in realtime. If a notification supports broadcasting, you should define a `toBroadcast` method on the notification class. This method will receive a `$notifiable` entity and should return a `BroadcastMessage` instance. The returned data will be encoded as JSON and broadcast to your JavaScript client. Let's take a look at an example `toBroadcast` method: + + use Illuminate\Notifications\Messages\BroadcastMessage; + + /** + * Get the broadcastable representation of the notification. + * + * @param mixed $notifiable + * @return BroadcastMessage + */ + public function toBroadcast($notifiable) + { + return new BroadcastMessage([ + 'invoice_id' => $this->invoice->id, + 'amount' => $this->invoice->amount, + ]); + } + +#### Broadcast Queue Configuration + +All broadcast notifications are queued for broadcasting. If you would like to configure the queue connection or queue name that is used to the queue the broadcast operation, you may use the `onConnection` and `onQueue` methods of the `BroadcastMessage`: + + return new BroadcastMessage($data) + ->onConnection('sqs') + ->onQueue('broadcasts'); + +> {tip} In addition to the data you specify, broadcast notifications will also contain a `type` field containing the class name of the notification. + + +### Listening For Notifications + +Notifications will broadcast on a private channel formatted using a `{notifiable}.{id}` convention. So, if you are sending a notification to a `App\User` instance with an ID of `1`, the notification will be broadcast on the `App.User.1` private channel. When using [Laravel Echo](/docs/{{version}}/broadcasting), you may easily listen for notifications on a channel using the `notification` helper method: + + Echo.private('App.User.' + userId) + .notification((notification) => { + console.log(notification.type); + }); + +#### Customizing The Notification Channel + +If you would like to customize which channels a notifiable entity receives its broadcast notifications on, you may define a `receivesBroadcastNotificationsOn` method on the notifiable entity: + + id), + ]; + } + } + + +## SMS Notifications + + +### Prerequisites + +Sending SMS notifications in Laravel is powered by [Nexmo](https://www.nexmo.com/). Before you can send notifications via Nexmo, you need to install the `nexmo/client` Composer package and add a few configuration options to your `config/services.php` configuration file. You may copy the example configuration below to get started: + + 'nexmo' => [ + 'key' => env('NEXMO_KEY'), + 'secret' => env('NEXMO_SECRET'), + 'sms_from' => '15556666666', + ], + +The `sms_from` option is the phone number that your SMS messages will be sent from. You should generate a phone number for your application in the Nexmo control panel. + + +### Formatting SMS Notifications + +If a notification supports being sent as a SMS, you should define a `toNexmo` method on the notification class. This method will receive a `$notifiable` entity and should return a `Illuminate\Notifications\Messages\NexmoMessage` instance: + + /** + * Get the Nexmo / SMS representation of the notification. + * + * @param mixed $notifiable + * @return NexmoMessage + */ + public function toNexmo($notifiable) + { + return (new NexmoMessage) + ->content('Your SMS message content'); + } + +#### Unicode Content + +If your SMS message will contain unicode characters, you should call the `unicode` method when constructing the `NexmoMessage` instance: + + /** + * Get the Nexmo / SMS representation of the notification. + * + * @param mixed $notifiable + * @return NexmoMessage + */ + public function toNexmo($notifiable) + { + return (new NexmoMessage) + ->content('Your unicode message') + ->unicode(); + } + + +### Customizing The "From" Number + +If you would like to send some notifications from a phone number that is different from the phone number specified in your `config/services.php` file, you may use the `from` method on a `NexmoMessage` instance: + + /** + * Get the Nexmo / SMS representation of the notification. + * + * @param mixed $notifiable + * @return NexmoMessage + */ + public function toNexmo($notifiable) + { + return (new NexmoMessage) + ->content('Your SMS message content') + ->from('15554443333'); + } + + +### Routing SMS Notifications + +When sending notifications via the `nexmo` channel, the notification system will automatically look for a `phone_number` attribute on the notifiable entity. If you would like to customize the phone number the notification is delivered to, define a `routeNotificationForNexmo` method on the entity: + + phone; + } + } + + +## Slack Notifications + + +### Prerequisites + +Before you can send notifications via Slack, you must install the Guzzle HTTP library via Composer: + + composer require guzzlehttp/guzzle + +You will also need to configure an "Incoming Webhook" integration for your Slack team. This integration will provide you with a URL you may use when [routing Slack notifications](#routing-slack-notifications). + + +### Formatting Slack Notifications + +If a notification supports being sent as a Slack message, you should define a `toSlack` method on the notification class. This method will receive a `$notifiable` entity and should return a `Illuminate\Notifications\Messages\SlackMessage` instance. Slack messages may contain text content as well as an "attachment" that formats additional text or an array of fields. Let's take a look at a basic `toSlack` example: + + /** + * Get the Slack representation of the notification. + * + * @param mixed $notifiable + * @return SlackMessage + */ + public function toSlack($notifiable) + { + return (new SlackMessage) + ->content('One of your invoices has been paid!'); + } + +In this example we are just sending a single line of text to Slack, which will create a message that looks like the following: + + + +#### Customizing The Sender & Recipient + +You may use the `from` and `to` methods to customize the sender and recipient. The `from` method accepts a username and emoji identifier, while the `to` method accepts a channel or username: + + /** + * Get the Slack representation of the notification. + * + * @param mixed $notifiable + * @return SlackMessage + */ + public function toSlack($notifiable) + { + return (new SlackMessage) + ->from('Ghost', ':ghost:') + ->to('#other') + ->content('This will be sent to #other'); + } + + +### Slack Attachments + +You may also add "attachments" to Slack messages. Attachments provide richer formatting options than simple text messages. In this example, we will send an error notification about an exception that occurred in an application, including a link to view more details about the exception: + + /** + * Get the Slack representation of the notification. + * + * @param mixed $notifiable + * @return SlackMessage + */ + public function toSlack($notifiable) + { + $url = url('/exceptions/'.$this->exception->id); + + return (new SlackMessage) + ->error() + ->content('Whoops! Something went wrong.') + ->attachment(function ($attachment) use ($url) { + $attachment->title('Exception: File Not Found', $url) + ->content('File [background.jpg] was not found.'); + }); + } + +The example above will generate a Slack message that looks like the following: + + + +Attachments also allow you to specify an array of data that should be presented to the user. The given data will be presented in a table-style format for easy reading: + + /** + * Get the Slack representation of the notification. + * + * @param mixed $notifiable + * @return SlackMessage + */ + public function toSlack($notifiable) + { + $url = url('/invoices/'.$this->invoice->id); + + return (new SlackMessage) + ->success() + ->content('One of your invoices has been paid!') + ->attachment(function ($attachment) use ($url) { + $attachment->title('Invoice 1322', $url) + ->fields([ + 'Title' => 'Server Expenses', + 'Amount' => '$1,234', + 'Via' => 'American Express', + 'Was Overdue' => ':-1:', + ]); + }); + } + +The example above will create a Slack message that looks like the following: + + + +#### Markdown Attachment Content + +If some of your attachment fields contain Markdown, you may use the `markdown` method to instruct Slack to parse and display the given attachment fields as Markdown formatted text: + + /** + * Get the Slack representation of the notification. + * + * @param mixed $notifiable + * @return SlackMessage + */ + public function toSlack($notifiable) + { + $url = url('/exceptions/'.$this->exception->id); + + return (new SlackMessage) + ->error() + ->content('Whoops! Something went wrong.') + ->attachment(function ($attachment) use ($url) { + $attachment->title('Exception: File Not Found', $url) + ->content('File [background.jpg] was **not found**.') + ->markdown(['title', 'text']); + }); + } + + +### Routing Slack Notifications + +To route Slack notifications to the proper location, define a `routeNotificationForSlack` method on your notifiable entity. This should return the webhook URL to which the notification should be delivered. Webhook URLs may be generated by adding an "Incoming Webhook" service to your Slack team: + + slack_webhook_url; + } + } + + +## Notification Events + +When a notification is sent, the `Illuminate\Notifications\Events\NotificationSent` event is fired by the notification system. This contains the "notifiable" entity and the notification instance itself. You may register listeners for this event in your `EventServiceProvider`: + + /** + * The event listener mappings for the application. + * + * @var array + */ + protected $listen = [ + 'Illuminate\Notifications\Events\NotificationSent' => [ + 'App\Listeners\LogNotification', + ], + ]; + +> {tip} After registering listeners in your `EventServiceProvider`, use the `event:generate` Artisan command to quickly generate listener classes. + +Within an event listener, you may access the `notifiable`, `notification`, and `channel` properties on the event to learn more about the notification recipient or the notification itself: + + /** + * Handle the event. + * + * @param NotificationSent $event + * @return void + */ + public function handle(NotificationSent $event) + { + // $event->channel + // $event->notifiable + // $event->notification + } + + +## Custom Channels + +Laravel ships with a handful of notification channels, but you may want to write your own drivers to deliver notifications via other channels. Laravel makes it simple. To get started, define a class that contains a `send` method. The method should receive two arguments: a `$notifiable` and a `$notification`: + + toVoice($notifiable); + + // Send notification to the $notifiable instance... + } + } + +Once your notification channel class has been defined, you may simply return the class name from the `via` method of any of your notifications: + + ## Introduction -Laravelတွင် တခြား functions တွေ အသစ်ထည့်တဲ့အခါမှာ Packages တွေခွဲပြီးအသစ်ထပ်ထည့်တဲ့နည်းက သမရိုးကျ နည်းလမ်းကောင်းတခုဖြစ်ပါတယ်။ လူအများစုဆောင်းပြီး project တွေကို ဖန်တီးရာတဲ့အခါမှာ အရမ်းအသုံးတည့်တဲ့နည်းလမ်းဖြစ်ပါတယ်။ ဥပမာ [Carbon](https://github.com/briannesbitt/Carbon), or [Behat](https://github.com/Behat/Behat). +Packages are the primary way of adding functionality to Laravel. Packages might be anything from a great way to work with dates like [Carbon](https://github.com/briannesbitt/Carbon), or an entire BDD testing framework like [Behat](https://github.com/Behat/Behat). -သေချာတာပေါ့ဗျာ ၊ Packages တွေကို အသုံးပြုရာမှာ ပုံစံမျိုးစုံရှိပါတယ်။ တချိုဟာတွေက Laravel တစ်ခုတည်းမဟုတ်ပဲ အခြားခြားသော Framework တွေမှာပါ အလုပ်လုပ်တဲ့ stand-alone packages တွေဖြစ်တယ်။ အပေါ်က CarBon နဲ့ Behat လို packages တွေကတော့ Stand-alon တွေဖြစ်ပါတယ် ။ အဲဒီလိုဖန်တီးထားတဲ့ packages တွေကို Laravel မှာသုံးမယ်ဆိုရင်တော့ ထုံးစံတိုင်း "composer.json" ဖိုင်မှာ သွားထည့့်ပေးလိုက်တာနဲ့ သုံးပြုနိုင်မှာပါ။ +Of course, there are different types of packages. Some packages are stand-alone, meaning they work with any PHP framework. Carbon and Behat are examples of stand-alone packages. Any of these packages may be used with Laravel by simply requesting them in your `composer.json` file. -တခြားတချက်ကတော့ တခြား packages တွေက Laravel အတွက်ပဲလို့ အသေသတ်မှတ်ပီး ထုတ်လုပ်ထားတဲ့ packages တွေလဲ ရှိပါတယ် ။ ဥပမာ အရင် laravel version တွေမှာ တုန်းက "bundles" လို packages တွေမျိုးပါ။ အဲဒီ packages တွေမှာ routes, controllers, views, configuration, နဲ့ migrations ဖွဲ့စည်းထားပြီး laravel ရဲ့ လုပ်ဆောင်နိုင်မူတွေကို တိုးချဲ့ အသုံးပြုနိုင်ပါတယ်။ Stan-alone packages တစ်ခု ဖန်တီးဖို့ဆိုတာ အရမ်းခက်တဲ့ ကိစ္စတော့မဟုတ်ပါဘူး ၊ အခုအောက်မှာ ထပ်ဖော်ပြမယ့် နည်းလမ်းတွေအတိုင်း ဖန်တီးကြည့်နိုင်ပါတယ်။ +On the other hand, other packages are specifically intended for use with Laravel. These packages may have routes, controllers, views, and configuration specifically intended to enhance a Laravel application. This guide primarily covers the development of those packages that are Laravel specific. -Laravel အတွက် Packages တွေကို [Packagist](http://packagist.org)မှာတင်ပြီး ဖြန့်ချီနိုင်ပြီး [Composer](http://getcomposer.org) လို အရမ်းမိုက်တဲ့ Package destributuin tool တွေသုံးပြု ပြီး ဖန်တီးရမှာပါ။ + +### A Note On Facades - -## Creating A Package - -Laravel မှာသုံးပြုဖို့အတွက် packages တစ်ခုတည်ဆောက်ဖို့အတွက်ကတော့ 'workbench' Artisan command ကို အသုံးပြုပြီးလွယ်လွယ်ကူကူကိုဖန်တီးနိုင်ပါတယ်။ အဲလိုလုပ်ဖို့အတွက် ပထမဆုံး 'app/config/workbench.php' မှာ name နဲ့ email လေးအရင်သွားဖြည့်ပေးရပါတယ်။ အဲဒီ name နဲ့ email ကို အသစ်ဆောက်မယ့် packages တွေ က 'composer.json' မှာ ပြန်အသုံးပြုဖို့အတွက်ဖြစ်ပါတယ်။ကဲ့ ဒီလောက်ပြင်ဆင်ပြီးရင် package တစ်ခု တည်ဆောက်ဖို့ အဆင်သင့်ဖြစ်နေပါပြီ။အောက်က ကွန်မန်းကို Terminal(cmd) မှာ ထည့် run လိုက်ပါ။ - -#### Issuing The Workbench Artisan Command - - php artisan workbench vendor/package --resources - -အပေါ်က command ထဲမှာ vendor ဆိုတာက package တစ်ခုကို authors တွေခွဲရေးတဲ့အခါမှာ package name ကို ခွဲခွဲခြားခြားသိနိုင်အောင်ပေးထားတဲ့နာမည်ဖြစ်ပါတယ်။ Vendor ဆိုတာက အဲဒီ package ကို ဖန်တီးတဲ့လူဖြစ်ပြီး package ဆိုတာကတော့ ကိုယ်လုပ်တဲ့ package name ဖြစ်ပါတယ်။ ဥပမာ ကျွန်တော် Taylar Otwell က "Zapper" ဆိုတဲ့ package တစ်ခုတည်ဆောက်လိုက်ရင် Package name က 'Zapper' ဖြစ်ပြး Vendor name က Taylar ဖြစ်ပါတယ်။ပုံမှန်အားဖြင့်တော့ workbench က framework package တခုတည်ဆောက်ပါတယ်။ "--resources" command က workbench ကို `migrations`, `views`, `config`, စသဖြင့်လိုအပ်တဲ့ ဖိုင်တွေကို ဖန်တီးပေးဖို ့ပြောပါတယ်။ - -အပေါ်က 'Workbench' ကို run ပြီးပြီဆိုရင်တော့ ၊ ကိုယ်ပေးထားတဲ့ နာမည်အတိုင်းပဲ 'workbench' ဆိုတဲ့ဖိုဒါထဲမှာ vendor name နဲ့ ဖိုဒါတွေရောက်လာပြီး အထဲမှာ package နာမည်နဲ့ လိုအပ်တဲ့ဖိုင်တွေအကုန် အလိုလျောက်ရှိနေပါလိမ့်မယ်။ ပြီးရင်တော့ တည်ဆောက်လိုက်တဲ့ package ကို laravel ကနေ သုံးပြုနိုင်ရန်အတွက် 'ServiceProvider' ကြော်ငြာပေးရပါတယ်။ Service Provider ကို 'app/config/app.php' မှာ သွားထည့်ပေးရပါတယ်။အဲဒီမှာ သွားထည့်ပေးလိုက်ရင် workbench ထဲက package တွေကို laravel ကနေ အသုံးပြုနိုင်ပါပြီ။ Service Provider က '[Package]ServiceProvider' ကိုအသုံးပြုပါတယ်။ဥပမာအရဆိုရင် 'app/config/app.php' က Provider မှာ 'Taylor\Zapper\ZapperServiceProvider' ဆိုပြီး array ထဲမှာ သွားထည့်ပေးရမှာပါ။ - -အခုလို Provider မှာ သွားထည့်ပေးပြီးရင်တော့ packages ကို လိုအပ်သလိုမျိုး စတင် အသုံးပြုနိုပ်ပါပြီ။ ပထမဆုံး package structure နဲ ့ development workflow ကို အရင်လေ့လာသင့်ပါတယ်။ - -> **Note:** Service Provider cannot be found ဆိုပြီး error ပြနေရင် `php artisan dump-autoload` ကို root directory မှာ terminal(cmd) မှ တစ်ဆင့် run ပြီး ပြန်စမ်းကြည့်ပါ။ - - -## Package Structure - -'workbench' command ကို အသုံးပြုပြီးတဲ့အခါမှာ အဲဒီ command က ကိုယ်ဖန်တီးလိုက်တဲ့ packages ကို laravel နှင့် တွဲဖက်အသုံးပြုနိုင်အောင် အကုန်အလိုလျောက်ပြုလုပ်ပေးပါတယ်။ - -#### Basic Package Directory Structure - - /src - /Vendor - /Package - PackageServiceProvider.php - /config - /lang - /migrations - /views - /tests - /public - -အပေါ်က file structure ကိုအရင်လေ့လာကြည့်ရအောင်။ 'src/Vendor/Package' က တော့ 'ServiceProvider' ပါဝင်တဲ့အတွက် package's classes တွေရဲ့ အဓိကနေရာလို့ပြောရမှာပါ။ `config`, `lang`, `migrations`, နဲ့ `views' တွေကတော့ packages အတွက် လိုအပ်တဲ့ resources တွေပါဝင်မယ့်ဖိုင်တွေဖြစ်ပါတယ်။ -Packages တစ်ခုမှာလဲ Laravel မှာရှိတဲ့ resources တွေ အတိုင်း တည်ရှိနေမှာပါ။ +When writing a Laravel application, it generally does not matter if you use contracts or facades since both provide essentially equal levels of testability. However, when writing packages, it is best to use [contracts](/docs/{{version}}/contracts) instead of [facades](/docs/{{version}}/facades). Since your package will not have access to all of Laravel's testing helpers, it will be easier to mock or stub a contract than to mock a facade. ## Service Providers -Service providers ဖိုင်တွေကတော့ packages တွေရဲ့ အသက်ဖိုင်လို့ပြောရမှာပါ။ပုံမှန်အားဖြင့် Service Provider မှာ 'boot' နဲ့ 'register' ဆိုတဲ့ methodsနှစ်ခုပါဝင်ပါတယ်။ -ဒီ methods နှစ်ခုမှာပဲ အကုန်လုံးပြုလုပ်နိုင်ပါတယ်။ ဥပမာ routes ဖိုင်ချိတ်ဖို့ ၊IoC Container တွေ register bindings လုပ်ဖို့ ၊ events တွေထည့်ဖို့ ၊ အကုန်လုံးနည်းပါးကို ဒီ method နှစ်ခုတစ်ဆင့် အလုပ်လုပ်သွားမှာပါ။ - -"register" method က Service Provider ကို register ပြုလုပ်ပြီးတာနဲ့ အလုပ်လုပ်မယ့် method ဖြစ်ပါတယ်။ 'boot' method ကတော့ request အသက်မဝင်ခင်အချိန်ထိပဲ အလုပ်လုပ်မှာဖြစ်ပါတယ်။ ဒါဆိုရင်တော့ service provider ထဲက actions တွေ registe လုပ်ပြီးတဲ့အချိန် (သို ့) တခြား provider တစ်ခုရဲ့ service ကို ကျော်လွန်(override)အသုံးပြုလိုပါက 'boot' method ကို အသုံးပြုသင့်ပါတယ်။ - -'workbench' command နှင့် package တစ်ခုတည်ဆောက်လိုက်တာနဲ့ 'boot' method မှာ အောက်ဖော်ပြပါအတိုင်း action တစ်ခု ပါဝင်နေပါတယ်။ - - $this->package('vendor/package'); - -ဒီ method က laravel ကို packages ထဲက views,config, other resource တွေကို အသုံးပြုနိုင်အောင်လုပ်ပေးပါတယ်။ ပုံမှန်အားဖြင့်တော့ အဲဒီ ကုတ်ကို ပြုပြင်ဖို့မလိုအပ်ပါဘူး။ - -ပုံမှန်အားဖြင့် package တစ်ခုတည်ဆောက်ပြီးတဲ့အခါ အဲဒီ packages ရဲ့ resource တွေက 'vendor/package' အောက်မှာရှိပါတယ်။ဘယ်လိုဖြစ်ဖြစ် package method ကို argument နောက်တစ်ခု ထပ်ထည့်ပြီး package resource နေရာတွေကို လိုအပ်သလို အောက်ကပုံစံအတိုင်း ပြောင်းလဲနိုင်ပါသေးတယ်။ - - // Passing custom namespace to package method - $this->package('vendor/package', 'custom-namespace'); - - // Package resources now accessed via custom-namespace - $view = View::make('custom-namespace::foo'); - -Service provider classes တွေအတွက် app directory ထဲမှာ နေရာအတည်တစ်ကျ သတ်မှတ်ထားတာမျိုးလဲမရှိပါဘူး။ 'app' ထဲမှ 'Providers' namespace ပေးပြီး ထားချင်တဲ့နေရာမှာ ထားနိုင်ပါတယ်။ ဒဲဒီ class ဖိုင်တွေကို Composer's [auto-loading facilities](http://getcomposer.org/doc/01-basic-usage.md#autoloading) က သိမှတ်ပြုနေသ၍ အဲဒီ class ဖိုင်ထဲက class တွေကို app က ယူသုံးနိုင်မှာပါ။ - -'Package ထဲက resources ( ဥပမာ Configuration ၊ Views ) နေရာတွေကို ပြောင်းလိုက်ပြီဆိုရင် ပြောင်းလိုက်တဲ့နေရာကို 'package' methord မှာ တတိယမြောက် argument တစ်ခုအဖြစ် အောက်ပါအတိုင်းထည့်သင့်ပေးသင့်ပါတယ်။ - - $this->package('vendor/package', null, '/path/to/resources'); - - -## Deferred Providers - - -If you are writing a service provider that does not register any resources such as configuration or views, you may choose to make your provider "deferred". A deferred service provider is only loaded and registered when one of the services it provides is actually needed by the application IoC container. If none of the provider's services are needed for a given request cycle, the provider is never loaded. - -To defer the execution of your service provider, set the `defer` property on the provider to `true`: - - protected $defer = true; - -Next you should override the `provides` method from the base `Illuminate\Support\ServiceProvider` class and return an array of all of the bindings that your provider adds to the IoC container. For example, if your provider registers `package.service` and `package.another-service` in the IoC container, your `provides` method should look like this: - - public function provides() - { - return array('package.service', 'package.another-service'); - } - - -## Package Conventions - - -When utilizing resources from a package, such as configuration items or views, a double-colon syntax will generally be used: - -#### Loading A View From A Package - - return View::make('package::view.name'); - -#### Retrieving A Package Configuration Item - - return Config::get('package::group.option'); - -> **Note:** If your package contains migrations, consider prefixing the migration name with your package name to avoid potential class name conflicts with other packages. - - -## Development Workflow - - -When developing a package, it is useful to be able to develop within the context of an application, allowing you to easily view and experiment with your templates, etc. So, to get started, install a fresh copy of the Laravel framework, then use the `workbench` command to create your package structure. - -After the `workbench` command has created your package. You may `git init` from the `workbench/[vendor]/[package]` directory and `git push` your package straight from the workbench! This will allow you to conveniently develop the package in an application context without being bogged down by constant `composer update` commands. - -Since your packages are in the `workbench` directory, you may be wondering how Composer knows to autoload your package's files. When the `workbench` directory exists, Laravel will intelligently scan it for packages, loading their Composer autoload files when the application starts! - -If you need to regenerate your package's autoload files, you may use the `php artisan dump-autoload` command. This command will regenerate the autoload files for your root project, as well as any workbenches you have created. - -#### Running The Artisan Autoload Command - - php artisan dump-autoload - - -## Package Routing - -In prior versions of Laravel, a `handles` clause was used to specify which URIs a package could respond to. However, in Laravel 4, a package may respond to any URI. To load a routes file for your package, simply `include` it from within your service provider's `boot` method. - -#### Including A Routes File From A Service Provider - - public function boot() - { - $this->package('vendor/package'); - - include __DIR__.'/../../routes.php'; - } - -> **Note:** If your package is using controllers, you will need to make sure they are properly configured in your `composer.json` file's auto-load section. - - -## Package Configuration - -#### Accessing Package Configuration Files - -Some packages may require configuration files. These files should be defined in the same way as typical application configuration files. And, when using the default `$this->package` method of registering resources in your service provider, may be accessed using the usual "double-colon" syntax: - - Config::get('package::file.option'); - -#### Accessing Single File Package Configuration - -However, if your package contains a single configuration file, you may simply name the file `config.php`. When this is done, you may access the options directly, without specifying the file name: - - Config::get('package::option'); - -#### Registering A Resource Namespace Manually - -Sometimes, you may wish to register package resources such as views outside of the typical `$this->package` method. Typically, this would only be done if the resources were not in a conventional location. To register the resources manually, you may use the `addNamespace` method of the `View`, `Lang`, and `Config` classes: - - View::addNamespace('package', __DIR__.'/path/to/views'); - -Once the namespace has been registered, you may use the namespace name and the "double colon" syntax to access the resources: - - return View::make('package::view.name'); - -The method signature for `addNamespace` is identical on the `View`, `Lang`, and `Config` classes. - -### Cascading Configuration Files - -When other developers install your package, they may wish to override some of the configuration options. However, if they change the values in your package source code, they will be overwritten the next time Composer updates the package. Instead, the `config:publish` artisan command should be used: - - php artisan config:publish vendor/package - -When this command is executed, the configuration files for your application will be copied to `app/config/packages/vendor/package` where they can be safely modified by the developer! - -> **Note:** The developer may also create environment specific configuration files for your package by placing them in `app/config/packages/vendor/package/environment`. - - -## Package Views - -If you are using a package in your application, you may occasionally wish to customize the package's views. You can easily export the package views to your own `app/views` directory using the `view:publish` Artisan command: - - php artisan view:publish vendor/package - -This command will move the package's views into the `app/views/packages` directory. If this directory doesn't already exist, it will be created when you run the command. Once the views have been published, you may tweak them to your liking! The exported views will automatically take precedence over the package's own view files. - - -## Package Migrations - -#### Creating Migrations For Workbench Packages - -You may easily create and run migrations for any of your packages. To create a migration for a package in the workbench, use the `--bench` option: +[Service providers](/docs/{{version}}/providers) are the connection points between your package and Laravel. A service provider is responsible for binding things into Laravel's [service container](/docs/{{version}}/container) and informing Laravel where to load package resources such as views, configuration, and localization files. - php artisan migrate:make create_users_table --bench="vendor/package" +A service provider extends the `Illuminate\Support\ServiceProvider` class and contains two methods: `register` and `boot`. The base `ServiceProvider` class is located in the `illuminate/support` Composer package, which you should add to your own package's dependencies. To learn more about the structure and purpose of service providers, check out [their documentation](/docs/{{version}}/providers). -#### Running Migrations For Workbench Packages + +## Routing + +To define routes for your package, pass the routes file path to the `loadRoutesFrom` method from within your package service provider's `boot` method. From within your routes file, you may use the `Illuminate\Support\Facades\Route` facade to [register routes](/docs/{{version}}/routing) just as you would within a typical Laravel application: + + /** + * Perform post-registration booting of services. + * + * @return void + */ + public function boot() + { + $this->loadRoutesFrom(__DIR__.'/path/to/routes.php'); + } - php artisan migrate --bench="vendor/package" + +## Resources -#### Running Migrations For An Installed Package + +### Configuration -Packages ထဲမှာ database migrate လုပ်ဖို့အတွက် workbench ထဲမှာ -To run migrations for a finished package that was installed via Composer into the `vendor` directory, you may use the `--package` directive: +Typically, you will need to publish your package's configuration file to the application's own `config` directory. This will allow users of your package to easily override your default configuration options. To allow your configuration files to be published, call the `publishes` method from the `boot` method of your service provider: - php artisan migrate --package="vendor/package" + /** + * Perform post-registration booting of services. + * + * @return void + */ + public function boot() + { + $this->publishes([ + __DIR__.'/path/to/config/courier.php' => config_path('courier.php'), + ]); + } - -## Package Assets +Now, when users of your package execute Laravel's `vendor:publish` command, your file will be copied to the specified publish location. Of course, once your configuration has been published, its values may be accessed like any other configuration file: -#### Moving Package Assets To Public -'packages' တွေမှာ 'Javascript, Css, images လို assets တွေပါကောင်းပါနိုင်ပါတယ်။ အဲဒီ assets တွေကို app မှ တဆင့်တန်းဆွဲခေါ်သုံးဖို့မဖြစ်နိုင်ပါဘူး ။ အဲဒီအတွက် 'package' ထဲက assets တွေကို public အောက်ကို ပြောင်းထည့်ပေးဖို့လိုအပ်ပါတယ်။ အဲဒီအတွက် `asset:publish` ကွန်မန်း ကို အောက်ကအတိုင်း အသုံးပြုပြီး ပြောင်းထည့်ပေးနိုင်ပါတယ်။ + $value = config('courier.option'); - php artisan asset:publish +> {note} You should not define Closures in your configuration files. They can not be serialized correctly when users execute the `config:cache` Artisan command. - php artisan asset:publish vendor/package +#### Default Package Configuration + +You may also merge your own package configuration file with the application's published copy. This will allow your users to define only the options they actually want to override in the published copy of the configuration. To merge the configurations, use the `mergeConfigFrom` method within your service provider's `register` method: -တကယ်လို တည်ဆောက်ထားတဲ့ 'package' က 'workbench' အောက်မှာပဲရှိသေးရင်တော့ ' --bench ' ကိုအောက်ပါအတိုင်းထပ်ထည့်ပြီးရေးပေးရပါတယ်။ + /** + * Register bindings in the container. + * + * @return void + */ + public function register() + { + $this->mergeConfigFrom( + __DIR__.'/path/to/config/courier.php', 'courier' + ); + } - php artisan asset:publish --bench="vendor/package" +> {note} This method only merges the first level of the configuration array. If your users partially define a multi-dimensional configuration array, the missing options will not be merged. -ဒီကွန်မန်းက package ထဲမှ assets တွေကို 'public/packages' ထဲကို သက်ဆိုင်ရင် package နဲ့ vendor နာမည်တွေအလိုက်ဖိုဒါတွေ အလိုလျောက်ဆောက်ပြီး သိမ်းဆည်းပေးသွားမှာပါ။ ဥပမာ 'workbench' အောက်မှာ 'usersape/kusod' ဆိုပြီး packages ဆောက်ထားရင် 'public/packages/userscape/kudos' ဆိုပြီး ရောက်သွားမှာပါ။ ဒီလိုလုပ်ခြင်းအားဖြင့် asset တွေနဲ့ပက်သက်ပြီး လုံခြုံရေးဆိုင်ရာ အားသာချက်များ ရရှိနိုင်ပါတယ်။ + +### Routes - -## Publishing Packages +If your package contains routes, you may load them using the `loadRoutesFrom` method. This method will automatically determine if the application's routes are cached and will not load your routes file if the routes have already been cached: -ကိုယ်တည်ဆောက်ထားတဲ့'Package' က အသုံးပြုဖို ့အားလုံးပြင်ဆင်ပြီးသွားရင်တော့ [Packagist](http://packagist.org) ကို တခြားသူတွေပါသုံးပြုနိုင်အောင် တင်ထားပေးသင့်ပါတယ်။ တကယ်လို့ ကိုယ် တည်ဆောက်လိုက်တဲ့ 'package' က laravel အတွက်ပဲ သီးသန့်တည်ဆောက်ထားရင်တော့ 'composer.json' မှာ 'laravel' ဆိုပြီး tag ထည့်ပေးဖို့လိုအပ်ပါတယ်။ + /** + * Perform post-registration booting of services. + * + * @return void + */ + public function boot() + { + $this->loadRoutesFrom(__DIR__.'/routes.php'); + } + +### Migrations -Also, it is courteous and helpful to tag your releases so that developers can depend on stable versions when requesting your package in their `composer.json` files. If a stable version is not ready, consider using the `branch-alias` Composer directive. +If your package contains [database migrations](/docs/{{version}}/migrations), you may use the `loadMigrationsFrom` method to inform Laravel how to load them. The `loadMigrationsFrom` method accepts the path to your package's migrations as its only argument: -Once your package has been published, feel free to continue developing it within the application context created by `workbench`. This is a great way to continue to conveniently develop the package even after it has been published. + /** + * Perform post-registration booting of services. + * + * @return void + */ + public function boot() + { + $this->loadMigrationsFrom(__DIR__.'/path/to/migrations'); + } -Some organizations choose to host their own private repository of packages for their own developers. If you are interested in doing this, review the documentation for the [Satis](http://github.com/composer/satis) project provided by the Composer team. +Once your package's migrations have been registered, they will automatically be run when the `php artisan migrate` command is executed. You do not need to export them to the application's main `database/migrations` directory. + + +### Translations + +If your package contains [translation files](/docs/{{version}}/localization), you may use the `loadTranslationsFrom` method to inform Laravel how to load them. For example, if your package is named `courier`, you should add the following to your service provider's `boot` method: + + /** + * Perform post-registration booting of services. + * + * @return void + */ + public function boot() + { + $this->loadTranslationsFrom(__DIR__.'/path/to/translations', 'courier'); + } + +Package translations are referenced using the `package::file.line` syntax convention. So, you may load the `courier` package's `welcome` line from the `messages` file like so: + + echo trans('courier::messages.welcome'); + +#### Publishing Translations + +If you would like to publish your package's translations to the application's `resources/lang/vendor` directory, you may use the service provider's `publishes` method. The `publishes` method accepts an array of package paths and their desired publish locations. For example, to publish the translation files for the `courier` package, you may do the following: + + /** + * Perform post-registration booting of services. + * + * @return void + */ + public function boot() + { + $this->loadTranslationsFrom(__DIR__.'/path/to/translations', 'courier'); + + $this->publishes([ + __DIR__.'/path/to/translations' => resource_path('lang/vendor/courier'), + ]); + } + +Now, when users of your package execute Laravel's `vendor:publish` Artisan command, your package's translations will be published to the specified publish location. + + +### Views + +To register your package's [views](/docs/{{version}}/views) with Laravel, you need to tell Laravel where the views are located. You may do this using the service provider's `loadViewsFrom` method. The `loadViewsFrom` method accepts two arguments: the path to your view templates and your package's name. For example, if your package's name is `courier`, you would add the following to your service provider's `boot` method: + + /** + * Perform post-registration booting of services. + * + * @return void + */ + public function boot() + { + $this->loadViewsFrom(__DIR__.'/path/to/views', 'courier'); + } + +Package views are referenced using the `package::view` syntax convention. So, once your view path is registered in a service provider, you may load the `admin` view from the `courier` package like so: + + Route::get('admin', function () { + return view('courier::admin'); + }); + +#### Overriding Package Views + +When you use the `loadViewsFrom` method, Laravel actually registers two locations for your views: the application's `resources/views/vendor` directory and the directory you specify. So, using the `courier` example, Laravel will first check if a custom version of the view has been provided by the developer in `resources/views/vendor/courier`. Then, if the view has not been customized, Laravel will search the package view directory you specified in your call to `loadViewsFrom`. This makes it easy for package users to customize / override your package's views. + +#### Publishing Views + +If you would like to make your views available for publishing to the application's `resources/views/vendor` directory, you may use the service provider's `publishes` method. The `publishes` method accepts an array of package view paths and their desired publish locations: + + /** + * Perform post-registration booting of services. + * + * @return void + */ + public function boot() + { + $this->loadViewsFrom(__DIR__.'/path/to/views', 'courier'); + + $this->publishes([ + __DIR__.'/path/to/views' => resource_path('views/vendor/courier'), + ]); + } + +Now, when users of your package execute Laravel's `vendor:publish` Artisan command, your package's views will be copied to the specified publish location. + + +## Commands + +To register your package's Artisan commands with Laravel, you may use the `commands` method. This method expects an array of command class names. Once the commands have been registered, you may execute them using the [Artisan CLI](/docs/{{version}}/artisan): + + /** + * Bootstrap the application services. + * + * @return void + */ + public function boot() + { + if ($this->app->runningInConsole()) { + $this->commands([ + FooCommand::class, + BarCommand::class, + ]); + } + } + + +## Public Assets + +Your package may have assets such as JavaScript, CSS, and images. To publish these assets to the application's `public` directory, use the service provider's `publishes` method. In this example, we will also add a `public` asset group tag, which may be used to publish groups of related assets: + + /** + * Perform post-registration booting of services. + * + * @return void + */ + public function boot() + { + $this->publishes([ + __DIR__.'/path/to/assets' => public_path('vendor/courier'), + ], 'public'); + } + +Now, when your package's users execute the `vendor:publish` command, your assets will be copied to the specified publish location. Since you will typically need to overwrite the assets every time the package is updated, you may use the `--force` flag: + + php artisan vendor:publish --tag=public --force + + +## Publishing File Groups + +You may want to publish groups of package assets and resources separately. For instance, you might want to allow your users to publish your package's configuration files without being forced to publish your package's assets. You may do this by "tagging" them when calling the `publishes` method from a package's service provider. For example, let's use tags to define two publish groups in the `boot` method of a package service provider: + + /** + * Perform post-registration booting of services. + * + * @return void + */ + public function boot() + { + $this->publishes([ + __DIR__.'/../config/package.php' => config_path('package.php') + ], 'config'); + + $this->publishes([ + __DIR__.'/../database/migrations/' => database_path('migrations') + ], 'migrations'); + } + +Now your users may publish these groups separately by referencing their tag when executing the `vendor:publish` command: + + php artisan vendor:publish --tag=config diff --git a/pagination.md b/pagination.md old mode 100755 new mode 100644 index f87f16c..2a28f67 --- a/pagination.md +++ b/pagination.md @@ -1,140 +1,182 @@ # Pagination -- [ပြင်ဆင်ခြင်း](#configuration) -- [အသုံးအနှုန်း](#usage) -- [Appending To Pagination Links](#appending-to-pagination-links) -- [Converting To JSON](#converting-to-json) -- [Custom Presenters](#custom-presenters) +- [Introduction](#introduction) +- [Basic Usage](#basic-usage) + - [Paginating Query Builder Results](#paginating-query-builder-results) + - [Paginating Eloquent Results](#paginating-eloquent-results) + - [Manually Creating A Paginator](#manually-creating-a-paginator) +- [Displaying Pagination Results](#displaying-pagination-results) + - [Converting Results To JSON](#converting-results-to-json) +- [Customizing The Pagination View](#customizing-the-pagination-view) +- [Paginator Instance Methods](#paginator-instance-methods) - -## ပြင်ဆင်ခြင်း + +## Introduction -Frameworks တော်တော်များများအတွက်တော့ pagination ပြုလုပ်ဖို့အတွက် စိတ်ပျက်စရာ ကိစ္စတွေ ကြုံတွေ့နိုင်ပါတယ်။ Laravel ကတော့ ဒီကိစ္စကို လွယ်လွယ်ကူကူ ပဲပြုလုပ်နိုင်အောင် အဆင်သင့် ပြင်ဆင်ထားပေးပါတယ်။`app/config/view.php` ဖိုင်ထဲမှာ pagination အတွက် option တစ်ခု ပါရှိပါတယ်။ အဲ့ဒီ `pagination` option မှာ pagination links တွေအတွက် ဘယ် view ကိုအသုံးပြုသင့်တယ်ဆိုတာကို သတ်မှတ်ပေးထားနိုင်ပါတယ်။ ပုံမှန်အတိုင်းဆိုရင်တော့ Laravel မှာ pagination အတွက် view နှစ်ခုကို သတ်မှတ်ပေးထားပါတယ်။ +In other frameworks, pagination can be very painful. Laravel's paginator is integrated with the [query builder](/docs/{{version}}/queries) and [Eloquent ORM](/docs/{{version}}/eloquent) and provides convenient, easy-to-use pagination of database results out of the box. The HTML generated by the paginator is compatible with the [Bootstrap CSS framework](https://getbootstrap.com/). -`pagination::slider` ကိုအသုံးပြုမယ်ဆိုရင် လက်ရှိ view မှာဖော်ပြထားတဲ့ items အရေအတွက်ကိုအခြေခံပီးတော့ links တွေထုတ်ပေးပါတယ်။ `pagination::simple` view ကတော့ "previous" နဲ့ "next" button နှစ်ခုထုတ်ပေးပါတယ်။ အဲ့ဒီ view နှစ်ခုစလုံးဟာ Twitter Bootstrap နဲ့ အဆင်ပြေပြေတွဲဖက်အသုံးပြုနိုင်ပါတယ်။ + +## Basic Usage - -## အသုံးအနှုန်း + +### Paginating Query Builder Results -အချက်အလက်တွေကို paginate လုပ်လုပ်ဖို့အတွက် နည်းနည်းတွေ အများကြီးရှိပါတယ်။ အဲ့ဒီအထဲကမှ `paginate` method ကို Laravel ရဲ့ Query Builder သို့မဟုတ် Eloquent Model တွေနဲ့တဲသုံးတဲ့နည်းကတော့ အရိုးရှင်းဆုံးနည်းလမ်းဖြစ်ပါတယ်။ +There are several ways to paginate items. The simplest is by using the `paginate` method on the [query builder](/docs/{{version}}/queries) or an [Eloquent query](/docs/{{version}}/eloquent). The `paginate` method automatically takes care of setting the proper limit and offset based on the current page being viewed by the user. By default, the current page is detected by the value of the `page` query string argument on the HTTP request. Of course, this value is automatically detected by Laravel, and is also automatically inserted into links generated by the paginator. -#### Paginating Database Results +In this example, the only argument passed to the `paginate` method is the number of items you would like displayed "per page". In this case, let's specify that we would like to display `15` items per page: - $users = DB::table('users')->paginate(15); + paginate(15); - $someUsers = User::where('votes', '>', 100)->paginate(15); + return view('user.index', ['users' => $users]); + } + } -`paginate` method ကို passing ပေးလိုက်တဲ့ argument(number) ဟာ စာမျက်နှာတစ်ခုပေါ်မှာ အချက်အလက် ဘယ်လောက်ပေါ်မယ်ဆိုတဲ့ အရေအတွက်ဖြစ်ပါတယ်။ Pagination links တွေကို view မှာပြန်ပြဖို့အတွက်တော့ `links` method ကိုအသုံးပြုနိုင်ပါတယ်။ +> {note} Currently, pagination operations that use a `groupBy` statement cannot be executed efficiently by Laravel. If you need to use a `groupBy` with a paginated result set, it is recommended that you query the database and create a paginator manually. -
    - - name; ?> - -
    +#### "Simple Pagination" - links(); ?> +If you only need to display simple "Next" and "Previous" links in your pagination view, you may use the `simplePaginate` method to perform a more efficient query. This is very useful for large datasets when you do not need to display a link for each page number when rendering your view: -လက်ရှိ စာမျက်နှာနဲ့ပတ်သက်ပြီး framework ကို ဘာပြင်ဆင်မှုမှ မလုပ်ခဲ့တာကို သတိပြုမိမှာပါ။ အဲ့ဒီအတွက် laravel က အလိုအလျောက်ဆုံးဖြတ်ပေးပါတယ်။ + $users = DB::table('users')->simplePaginate(15); -Pagination အတွက် custom view ကိုအသုံးပြုချင်ရင်တော့ `links` method ထဲမှာ view ကို passing ပေးလိုက်ရုံပါပဲ။ + +### Paginating Eloquent Results - links('view.name'); ?> +You may also paginate [Eloquent](/docs/{{version}}/eloquent) queries. In this example, we will paginate the `User` model with `15` items per page. As you can see, the syntax is nearly identical to paginating query builder results: -Pagination information တွေကိုလဲ အောက်ပါ methods တွေကိုအသုံးပြုပြီး ရယူနိုင်ပါတယ်။ + $users = App\User::paginate(15); -- `getCurrentPage` -- `getLastPage` -- `getPerPage` -- `getTotal` -- `getFrom` -- `getTo` -- `count` +Of course, you may call `paginate` after setting other constraints on the query, such as `where` clauses: + $users = User::where('votes', '>', 100)->paginate(15); -#### "Simple Pagination" +You may also use the `simplePaginate` method when paginating Eloquent models: -အကယ်၍ pagination view မှာ "next" နဲ့ "previous" links တွေကိုပဲပြချင်ရင်တော့ ပိုပြီးအဆင်ပြေတဲ့ query ကိုပြုလုပ်ပေးနိုင်တဲ့ `simplePaginate` method ကိုအသုံးပြုနိုင်ပါတယ်။ view မှာ page numbers တွေအတိအကျဖော်ပြစရာမလိုတဲ့အတွက် data တွေအများကြီးကို paginate လုပ်ရာမှာ ပိုမို အဆင်ပြေစေပါတယ်။ + $users = User::where('votes', '>', 100)->simplePaginate(15); - $someUsers = User::where('votes', '>', 100)->simplePaginate(15); + +### Manually Creating A Paginator -#### Creating A Paginator Manually +Sometimes you may wish to create a pagination instance manually, passing it an array of items. You may do so by creating either an `Illuminate\Pagination\Paginator` or `Illuminate\Pagination\LengthAwarePaginator` instance, depending on your needs. -အကယ်၍ pagination ကို manually ပြုလုပ်ချင်ရင် `Paginator::make` method ကိုအသုံးပြုနိုင်ပါတယ်။ +The `Paginator` class does not need to know the total number of items in the result set; however, because of this, the class does not have methods for retrieving the index of the last page. The `LengthAwarePaginator` accepts almost the same arguments as the `Paginator`; however, it does require a count of the total number of items in the result set. - $paginator = Paginator::make($items, $totalItems, $perPage); +In other words, the `Paginator` corresponds to the `simplePaginate` method on the query builder and Eloquent, while the `LengthAwarePaginator` corresponds to the `paginate` method. -#### Customizing The Paginator URI +> {note} When manually creating a paginator instance, you should manually "slice" the array of results you pass to the paginator. If you're unsure how to do this, check out the [array_slice](https://secure.php.net/manual/en/function.array-slice.php) PHP function. -Paginator ကအသုံးပြုတဲ့ URI ကိုလဲ `setBaseUrl` method ကိုအသုံးပြုပြီး ပြင်ဆင်နိုင်ပါတယ်။ + +## Displaying Pagination Results - $users = User::paginate(); +When calling the `paginate` method, you will receive an instance of `Illuminate\Pagination\LengthAwarePaginator`. When calling the `simplePaginate` method, you will receive an instance of `Illuminate\Pagination\Paginator`. These objects provide several methods that describe the result set. In addition to these helpers methods, the paginator instances are iterators and may be looped as an array. So, once you have retrieved the results, you may display the results and render the page links using [Blade](/docs/{{version}}/blade): - $users->setBaseUrl('custom/url'); +
    + @foreach ($users as $user) + {{ $user->name }} + @endforeach +
    -အပေါ်မှာပြထားတဲ့ ဥပမာအရဆိုရင် pagination URLs ဟာ http://example.com/custom/url?page=2 ပုံစံဖြစ်သွားမှာပါ။ + {{ $users->links() }} - -## Appending To Pagination Links +The `links` method will render the links to the rest of the pages in the result set. Each of these links will already contain the proper `page` query string variable. Remember, the HTML generated by the `links` method is compatible with the [Bootstrap CSS framework](https://getbootstrap.com). -သင့်အနေနဲ့ `appends` method ကိုအသုံးပြုပြီး query string တွေကို pagination links တွေဆီကို ထပ်ပေါင်းထည့်လို့ရပါတယ်။ +#### Customizing The Paginator URI - appends(array('sort' => 'votes'))->links(); ?> +The `withPath` method allows you to customize the URI used by the paginator when generating links. For example, if you want the paginator to generate links like `http://example.com/custom/url?page=N`, you should pass `custom/url` to the `withPath` method: -အပေါ်မှာရေးထားတဲ့ အတိုင်းဆိုရင် URLs ဟာ အောက်ပါပုံစံနဲ့ထွက်လာမှာပါ။ + Route::get('users', function () { + $users = App\User::paginate(15); - http://example.com/something?page=2&sort=votes + $users->withPath('custom/url'); -Paginator's URLs မှာ "hash fragment" ထပ်ပေါင်းထည့်ချင်ရင်တော့ `fragment` method ကိုအသုံးပြုနိုင်ပါတယ်။ + // + }); - fragment('foo')->links(); ?> +#### Appending To Pagination Links -အပေါ်က mehtod call ဟာ URLs ကို အောက်ပါအတိုင်းထုတ်ပေးပါလိမ့်မယ်။ +You may append to the query string of pagination links using the `appends` method. For example, to append `sort=votes` to each pagination link, you should make the following call to `appends`: - http://example.com/something?page=2#foo + {{ $users->appends(['sort' => 'votes'])->links() }} - -## Converting To JSON +If you wish to append a "hash fragment" to the paginator's URLs, you may use the `fragment` method. For example, to append `#foo` to the end of each pagination link, make the following call to the `fragment` method: -The `Paginator` class implements the `Illuminate\Support\Contracts\JsonableInterface` contract and exposes the `toJson` method. You can may also convert a `Paginator` instance to JSON by returning it from a route. The JSON'd form of the instance will include some "meta" information such as `total`, `current_page`, `last_page`, `from`, and `to`. The instance's data will be available via the `data` key in the JSON array. + {{ $users->fragment('foo')->links() }} - -## Custom Presenters + +### Converting Results To JSON -Pagination ရဲ့ UI style ဟာ default အနေအထားမှာ Bootstrap Frontend Framework က pagination ပုံစံအတိုင်းပြုလုပ်ပေးထားပါတယ်။ သင့်အနေနဲ့ customize presenter နဲ့ အသုံးပြုချင်တယ်ဆိုရင်လဲ အသုံးပြုလို့ရနိုင်ပါတယ်။ +The Laravel paginator result classes implement the `Illuminate\Contracts\Support\Jsonable` Interface contract and expose the `toJson` method, so it's very easy to convert your pagination results to JSON. You may also convert a paginator instance to JSON by simply returning it from a route or controller action: -### Extending The Abstract Presenter + Route::get('users', function () { + return App\User::paginate(); + }); -`Illuminate\Pagination\Presenter` class ကို extend လုပ်ပြီး အဲ့ဒီ class ရဲ့ abstract methods တွေကို implement ပြုလုပ်ပြီးပြောငး်လဲ အသုံးပြုနိုင်ပါတယ်။ အောက်မှာ ပြထားတဲ့ ဥပမာကတော့ Zurb Foundation ရဲ့ ပုံစံကိုပြောင်းလဲ အသုံးပြုထားတာဖြစ်ပါတယ်။ +The JSON from the paginator will include meta information such as `total`, `current_page`, `last_page`, and more. The actual result objects will be available via the `data` key in the JSON array. Here is an example of the JSON created by returning a paginator instance from a route: - class ZurbPresenter extends Illuminate\Pagination\Presenter { + { + "total": 50, + "per_page": 15, + "current_page": 1, + "last_page": 4, + "next_page_url": "http://laravel.app?page=2", + "prev_page_url": null, + "from": 1, + "to": 15, + "data":[ + { + // Result Object + }, + { + // Result Object + } + ] + } - public function getActivePageWrapper($text) - { - return '
  • '.$text.'
  • '; - } + +## Customizing The Pagination View - public function getDisabledTextWrapper($text) - { - return '
  • '.$text.'
  • '; - } +By default, the views rendered to display the pagination links are compatible with the Bootstrap CSS framework. However, if you are not using Bootstrap, you are free to define your own views to render these links. When calling the `links` method on a paginator instance, pass the view name as the first argument to the method: - public function getPageLinkWrapper($url, $page) - { - return '
  • '.$page.'
  • '; - } + {{ $paginator->links('view.name') }} - } + // Passing data to the view... + {{ $paginator->links('view.name', ['foo' => 'bar']) }} + +However, the easiest way to customize the pagination views is by exporting them to your `resources/views/vendor` directory using the `vendor:publish` command: + + php artisan vendor:publish --tag=laravel-pagination + +This command will place the views in the `resources/views/vendor/pagination` directory. The `default.blade.php` file within this directory corresponds to the default pagination view. Simply edit this file to modify the pagination HTML. -### Using The Custom Presenter + +## Paginator Instance Methods -ပထမဦးဆုံး custom presenter ပြုလုပ်လို့တဲ့ view ဖိုင်ကို `app/views` အောက်မှာ ပြုလုပ်ပေးလိုက်ပါ။ ပြီးရင် `app/config/view.php` အောက်မှာရှိတဲ့ `pagination` `pagination::slider-3` နေရာမှာ အသစ်လုပ်ထားတဲ့ view file ရဲ့ name နဲ့အစားထိုးလိုက်ပါ။ အပေါ်မှာပြထားတဲ့ Zurb Foundation အတိုင်းဆိုရင် သင့်ရဲ့ view ဖိုင်အသစ်ဟာ အောက်ပါ ပုံစံအတိုင်းဖြစ်ရမှာပါ။ +Each paginator instance provides additional pagination information via the following methods: -
      - render(); ?> -
    +- `$results->count()` +- `$results->currentPage()` +- `$results->firstItem()` +- `$results->hasMorePages()` +- `$results->lastItem()` +- `$results->lastPage() (Not available when using simplePaginate)` +- `$results->nextPageUrl()` +- `$results->perPage()` +- `$results->previousPageUrl()` +- `$results->total() (Not available when using simplePaginate)` +- `$results->url($page)` diff --git a/passport.md b/passport.md new file mode 100644 index 0000000..356faad --- /dev/null +++ b/passport.md @@ -0,0 +1,659 @@ +# API Authentication (Passport) + +- [Introduction](#introduction) +- [Installation](#installation) + - [Frontend Quickstart](#frontend-quickstart) +- [Configuration](#configuration) + - [Token Lifetimes](#token-lifetimes) +- [Issuing Access Tokens](#issuing-access-tokens) + - [Managing Clients](#managing-clients) + - [Requesting Tokens](#requesting-tokens) + - [Refreshing Tokens](#refreshing-tokens) +- [Password Grant Tokens](#password-grant-tokens) + - [Creating A Password Grant Client](#creating-a-password-grant-client) + - [Requesting Tokens](#requesting-password-grant-tokens) + - [Requesting All Scopes](#requesting-all-scopes) +- [Implicit Grant Tokens](#implicit-grant-tokens) +- [Client Credentials Grant Tokens](#client-credentials-grant-tokens) +- [Personal Access Tokens](#personal-access-tokens) + - [Creating A Personal Access Client](#creating-a-personal-access-client) + - [Managing Personal Access Tokens](#managing-personal-access-tokens) +- [Protecting Routes](#protecting-routes) + - [Via Middleware](#via-middleware) + - [Passing The Access Token](#passing-the-access-token) +- [Token Scopes](#token-scopes) + - [Defining Scopes](#defining-scopes) + - [Assigning Scopes To Tokens](#assigning-scopes-to-tokens) + - [Checking Scopes](#checking-scopes) +- [Consuming Your API With JavaScript](#consuming-your-api-with-javascript) +- [Events](#events) + + +## Introduction + +Laravel already makes it easy to perform authentication via traditional login forms, but what about APIs? APIs typically use tokens to authenticate users and do not maintain session state between requests. Laravel makes API authentication a breeze using Laravel Passport, which provides a full OAuth2 server implementation for your Laravel application in a matter of minutes. Passport is built on top of the [League OAuth2 server](https://github.com/thephpleague/oauth2-server) that is maintained by Alex Bilbie. + +> {note} This documentation assumes you are already familiar with OAuth2. If you do not know anything about OAuth2, consider familiarizing yourself with the general terminology and features of OAuth2 before continuing. + + +## Installation + +To get started, install Passport via the Composer package manager: + + composer require laravel/passport + +Next, register the Passport service provider in the `providers` array of your `config/app.php` configuration file: + + Laravel\Passport\PassportServiceProvider::class, + +The Passport service provider registers its own database migration directory with the framework, so you should migrate your database after registering the provider. The Passport migrations will create the tables your application needs to store clients and access tokens: + + php artisan migrate + +> {note} If you are not going to use Passport's default migrations, you should call the `Passport::ignoreMigrations` method in the `register` method of your `AppServiceProvider`. You may export the default migrations using `php artisan vendor:publish --tag=passport-migrations`. + +Next, you should run the `passport:install` command. This command will create the encryption keys needed to generate secure access tokens. In addition, the command will create "personal access" and "password grant" clients which will be used to generate access tokens: + + php artisan passport:install + +After running this command, add the `Laravel\Passport\HasApiTokens` trait to your `App\User` model. This trait will provide a few helper methods to your model which allow you to inspect the authenticated user's token and scopes: + + 'App\Policies\ModelPolicy', + ]; + + /** + * Register any authentication / authorization services. + * + * @return void + */ + public function boot() + { + $this->registerPolicies(); + + Passport::routes(); + } + } + +Finally, in your `config/auth.php` configuration file, you should set the `driver` option of the `api` authentication guard to `passport`. This will instruct your application to use Passport's `TokenGuard` when authenticating incoming API requests: + + 'guards' => [ + 'web' => [ + 'driver' => 'session', + 'provider' => 'users', + ], + + 'api' => [ + 'driver' => 'passport', + 'provider' => 'users', + ], + ], + + +### Frontend Quickstart + +> {note} In order to use the Passport Vue components, you must be using the [Vue](https://vuejs.org) JavaScript framework. These components also use the Bootstrap CSS framework. However, even if you are not using these tools, the components serve as a valuable reference for your own frontend implementation. + +Passport ships with a JSON API that you may use to allow your users to create clients and personal access tokens. However, it can be time consuming to code a frontend to interact with these APIs. So, Passport also includes pre-built [Vue](https://vuejs.org) components you may use as an example implementation or starting point for your own implementation. + +To publish the Passport Vue components, use the `vendor:publish` Artisan command: + + php artisan vendor:publish --tag=passport-components + +The published components will be placed in your `resources/assets/js/components` directory. Once the components have been published, you should register them in your `resources/assets/js/app.js` file: + + Vue.component( + 'passport-clients', + require('./components/passport/Clients.vue') + ); + + Vue.component( + 'passport-authorized-clients', + require('./components/passport/AuthorizedClients.vue') + ); + + Vue.component( + 'passport-personal-access-tokens', + require('./components/passport/PersonalAccessTokens.vue') + ); + +After registering the components, make sure to run `npm run dev` to recompile your assets. Once you have recompiled your assets, you may drop the components into one of your application's templates to get started creating clients and personal access tokens: + + + + + + +## Configuration + + +### Token Lifetimes + +By default, Passport issues long-lived access tokens that never need to be refreshed. If you would like to configure a shorter token lifetime, you may use the `tokensExpireIn` and `refreshTokensExpireIn` methods. These methods should be called from the `boot` method of your `AuthServiceProvider`: + + use Carbon\Carbon; + + /** + * Register any authentication / authorization services. + * + * @return void + */ + public function boot() + { + $this->registerPolicies(); + + Passport::routes(); + + Passport::tokensExpireIn(Carbon::now()->addDays(15)); + + Passport::refreshTokensExpireIn(Carbon::now()->addDays(30)); + } + + +## Issuing Access Tokens + +Using OAuth2 with authorization codes is how most developers are familiar with OAuth2. When using authorization codes, a client application will redirect a user to your server where they will either approve or deny the request to issue an access token to the client. + + +### Managing Clients + +First, developers building applications that need to interact with your application's API will need to register their application with yours by creating a "client". Typically, this consists of providing the name of their application and a URL that your application can redirect to after users approve their request for authorization. + +#### The `passport:client` Command + +The simplest way to create a client is using the `passport:client` Artisan command. This command may be used to create your own clients for testing your OAuth2 functionality. When you run the `client` command, Passport will prompt you for more information about your client and will provide you with a client ID and secret: + + php artisan passport:client + +#### JSON API + +Since your users will not be able to utilize the `client` command, Passport provides a JSON API that you may use to create clients. This saves you the trouble of having to manually code controllers for creating, updating, and deleting clients. + +However, you will need to pair Passport's JSON API with your own frontend to provide a dashboard for your users to manage their clients. Below, we'll review all of the API endpoints for managing clients. For convenience, we'll use [Axios](https://github.com/mzabriskie/axios) to demonstrate making HTTP requests to the endpoints. + +> {tip} If you don't want to implement the entire client management frontend yourself, you can use the [frontend quickstart](#frontend-quickstart) to have a fully functional frontend in a matter of minutes. + +#### `GET /oauth/clients` + +This route returns all of the clients for the authenticated user. This is primarily useful for listing all of the user's clients so that they may edit or delete them: + + axios.get('/oauth/clients') + .then(response => { + console.log(response.data); + }); + +#### `POST /oauth/clients` + +This route is used to create new clients. It requires two pieces of data: the client's `name` and a `redirect` URL. The `redirect` URL is where the user will be redirected after approving or denying a request for authorization. + +When a client is created, it will be issued a client ID and client secret. These values will be used when requesting access tokens from your application. The client creation route will return the new client instance: + + const data = { + name: 'Client Name', + redirect: 'http://example.com/callback' + }; + + axios.post('/oauth/clients', data) + .then(response => { + console.log(response.data); + }) + .catch (response => { + // List errors on response... + }); + +#### `PUT /oauth/clients/{client-id}` + +This route is used to update clients. It requires two pieces of data: the client's `name` and a `redirect` URL. The `redirect` URL is where the user will be redirected after approving or denying a request for authorization. The route will return the updated client instance: + + const data = { + name: 'New Client Name', + redirect: 'http://example.com/callback' + }; + + axios.put('/oauth/clients/' + clientId, data) + .then(response => { + console.log(response.data); + }) + .catch (response => { + // List errors on response... + }); + +#### `DELETE /oauth/clients/{client-id}` + +This route is used to delete clients: + + axios.delete('/oauth/clients/' + clientId) + .then(response => { + // + }); + + +### Requesting Tokens + +#### Redirecting For Authorization + +Once a client has been created, developers may use their client ID and secret to request an authorization code and access token from your application. First, the consuming application should make a redirect request to your application's `/oauth/authorize` route like so: + + Route::get('/redirect', function () { + $query = http_build_query([ + 'client_id' => 'client-id', + 'redirect_uri' => 'http://example.com/callback', + 'response_type' => 'code', + 'scope' => '', + ]); + + return redirect('http://your-app.com/oauth/authorize?'.$query); + }); + +> {tip} Remember, the `/oauth/authorize` route is already defined by the `Passport::routes` method. You do not need to manually define this route. + +#### Approving The Request + +When receiving authorization requests, Passport will automatically display a template to the user allowing them to approve or deny the authorization request. If they approve the request, they will be redirected back to the `redirect_uri` that was specified by the consuming application. The `redirect_uri` must match the `redirect` URL that was specified when the client was created. + +If you would like to customize the authorization approval screen, you may publish Passport's views using the `vendor:publish` Artisan command. The published views will be placed in `resources/views/vendor/passport`: + + php artisan vendor:publish --tag=passport-views + +#### Converting Authorization Codes To Access Tokens + +If the user approves the authorization request, they will be redirected back to the consuming application. The consumer should then issue a `POST` request to your application to request an access token. The request should include the authorization code that was issued by your application when the user approved the authorization request. In this example, we'll use the Guzzle HTTP library to make the `POST` request: + + Route::get('/callback', function (Request $request) { + $http = new GuzzleHttp\Client; + + $response = $http->post('http://your-app.com/oauth/token', [ + 'form_params' => [ + 'grant_type' => 'authorization_code', + 'client_id' => 'client-id', + 'client_secret' => 'client-secret', + 'redirect_uri' => 'http://example.com/callback', + 'code' => $request->code, + ], + ]); + + return json_decode((string) $response->getBody(), true); + }); + +This `/oauth/token` route will return a JSON response containing `access_token`, `refresh_token`, and `expires_in` attributes. The `expires_in` attribute contains the number of seconds until the access token expires. + +> {tip} Like the `/oauth/authorize` route, the `/oauth/token` route is defined for you by the `Passport::routes` method. There is no need to manually define this route. + + +### Refreshing Tokens + +If your application issues short-lived access tokens, users will need to refresh their access tokens via the refresh token that was provided to them when the access token was issued. In this example, we'll use the Guzzle HTTP library to refresh the token: + + $http = new GuzzleHttp\Client; + + $response = $http->post('http://your-app.com/oauth/token', [ + 'form_params' => [ + 'grant_type' => 'refresh_token', + 'refresh_token' => 'the-refresh-token', + 'client_id' => 'client-id', + 'client_secret' => 'client-secret', + 'scope' => '', + ], + ]); + + return json_decode((string) $response->getBody(), true); + +This `/oauth/token` route will return a JSON response containing `access_token`, `refresh_token`, and `expires_in` attributes. The `expires_in` attribute contains the number of seconds until the access token expires. + + +## Password Grant Tokens + +The OAuth2 password grant allows your other first-party clients, such as a mobile application, to obtain an access token using an e-mail address / username and password. This allows you to issue access tokens securely to your first-party clients without requiring your users to go through the entire OAuth2 authorization code redirect flow. + + +### Creating A Password Grant Client + +Before your application can issue tokens via the password grant, you will need to create a password grant client. You may do this using the `passport:client` command with the `--password` option. If you have already run the `passport:install` command, you do not need to run this command: + + php artisan passport:client --password + + +### Requesting Tokens + +Once you have created a password grant client, you may request an access token by issuing a `POST` request to the `/oauth/token` route with the user's email address and password. Remember, this route is already registered by the `Passport::routes` method so there is no need to define it manually. If the request is successful, you will receive an `access_token` and `refresh_token` in the JSON response from the server: + + $http = new GuzzleHttp\Client; + + $response = $http->post('http://your-app.com/oauth/token', [ + 'form_params' => [ + 'grant_type' => 'password', + 'client_id' => 'client-id', + 'client_secret' => 'client-secret', + 'username' => 'taylor@laravel.com', + 'password' => 'my-password', + 'scope' => '', + ], + ]); + + return json_decode((string) $response->getBody(), true); + +> {tip} Remember, access tokens are long-lived by default. However, you are free to [configure your maximum access token lifetime](#configuration) if needed. + + +### Requesting All Scopes + +When using the password grant, you may wish to authorize the token for all of the scopes supported by your application. You can do this by requesting the `*` scope. If you request the `*` scope, the `can` method on the token instance will always return `true`. This scope may only be assigned to a token that is issued using the `password` grant: + + $response = $http->post('http://your-app.com/oauth/token', [ + 'form_params' => [ + 'grant_type' => 'password', + 'client_id' => 'client-id', + 'client_secret' => 'client-secret', + 'username' => 'taylor@laravel.com', + 'password' => 'my-password', + 'scope' => '*', + ], + ]); + + +## Implicit Grant Tokens + +The implicit grant is similar to the authorization code grant; however, the token is returned to the client without exchanging an authorization code. This grant is most commonly used for JavaScript or mobile applications where the client credentials can't be securely stored. To enable the grant, call the `enableImplicitGrant` method in your `AuthServiceProvider`: + + /** + * Register any authentication / authorization services. + * + * @return void + */ + public function boot() + { + $this->registerPolicies(); + + Passport::routes(); + + Passport::enableImplicitGrant(); + } + +Once a grant has been enabled, developers may use their client ID to request an access token from your application. The consuming application should make a redirect request to your application's `/oauth/authorize` route like so: + + Route::get('/redirect', function () { + $query = http_build_query([ + 'client_id' => 'client-id', + 'redirect_uri' => 'http://example.com/callback', + 'response_type' => 'token', + 'scope' => '', + ]); + + return redirect('http://your-app.com/oauth/authorize?'.$query); + }); + +> {tip} Remember, the `/oauth/authorize` route is already defined by the `Passport::routes` method. You do not need to manually define this route. + + +## Client Credentials Grant Tokens + +The client credentials grant is suitable for machine-to-machine authentication. For example, you might use this grant in a scheduled job which is performing maintenance tasks over an API. To retrieve a token, make a request to the `oauth/token` endpoint: + + $guzzle = new GuzzleHttp\Client; + + $response = $guzzle->post('http://your-app.com/oauth/token', [ + 'form_params' => [ + 'grant_type' => 'client_credentials', + 'client_id' => 'client-id', + 'client_secret' => 'client-secret', + 'scope' => 'your-scope', + ], + ]); + + echo json_decode((string) $response->getBody(), true); + + +## Personal Access Tokens + +Sometimes, your users may want to issue access tokens to themselves without going through the typical authorization code redirect flow. Allowing users to issue tokens to themselves via your application's UI can be useful for allowing users to experiment with your API or may serve as a simpler approach to issuing access tokens in general. + +> {note} Personal access tokens are always long-lived. Their lifetime is not modified when using the `tokensExpireIn` or `refreshTokensExpireIn` methods. + + +### Creating A Personal Access Client + +Before your application can issue personal access tokens, you will need to create a personal access client. You may do this using the `passport:client` command with the `--personal` option. If you have already run the `passport:install` command, you do not need to run this command: + + php artisan passport:client --personal + + +### Managing Personal Access Tokens + +Once you have created a personal access client, you may issue tokens for a given user using the `createToken` method on the `User` model instance. The `createToken` method accepts the name of the token as its first argument and an optional array of [scopes](#token-scopes) as its second argument: + + $user = App\User::find(1); + + // Creating a token without scopes... + $token = $user->createToken('Token Name')->accessToken; + + // Creating a token with scopes... + $token = $user->createToken('My Token', ['place-orders'])->accessToken; + +#### JSON API + +Passport also includes a JSON API for managing personal access tokens. You may pair this with your own frontend to offer your users a dashboard for managing personal access tokens. Below, we'll review all of the API endpoints for managing personal access tokens. For convenience, we'll use [Axios](https://github.com/mzabriskie/axios) to demonstrate making HTTP requests to the endpoints. + +> {tip} If you don't want to implement the personal access token frontend yourself, you can use the [frontend quickstart](#frontend-quickstart) to have a fully functional frontend in a matter of minutes. + +#### `GET /oauth/scopes` + +This route returns all of the [scopes](#token-scopes) defined for your application. You may use this route to list the scopes a user may assign to a personal access token: + + axios.get('/oauth/scopes') + .then(response => { + console.log(response.data); + }); + +#### `GET /oauth/personal-access-tokens` + +This route returns all of the personal access tokens that the authenticated user has created. This is primarily useful for listing all of the user's token so that they may edit or delete them: + + axios.get('/oauth/personal-access-tokens') + .then(response => { + console.log(response.data); + }); + +#### `POST /oauth/personal-access-tokens` + +This route creates new personal access tokens. It requires two pieces of data: the token's `name` and the `scopes` that should be assigned to the token: + + const data = { + name: 'Token Name', + scopes: [] + }; + + axios.post('/oauth/personal-access-tokens', data) + .then(response => { + console.log(response.data.accessToken); + }) + .catch (response => { + // List errors on response... + }); + +#### `DELETE /oauth/personal-access-tokens/{token-id}` + +This route may be used to delete personal access tokens: + + axios.delete('/oauth/personal-access-tokens/' + tokenId); + + +## Protecting Routes + + +### Via Middleware + +Passport includes an [authentication guard](/docs/{{version}}/authentication#adding-custom-guards) that will validate access tokens on incoming requests. Once you have configured the `api` guard to use the `passport` driver, you only need to specify the `auth:api` middleware on any routes that require a valid access token: + + Route::get('/user', function () { + // + })->middleware('auth:api'); + + +### Passing The Access Token + +When calling routes that are protected by Passport, your application's API consumers should specify their access token as a `Bearer` token in the `Authorization` header of their request. For example, when using the Guzzle HTTP library: + + $response = $client->request('GET', '/api/user', [ + 'headers' => [ + 'Accept' => 'application/json', + 'Authorization' => 'Bearer '.$accessToken, + ], + ]); + + +## Token Scopes + + + +### Defining Scopes + +Scopes allow your API clients to request a specific set of permissions when requesting authorization to access an account. For example, if you are building an e-commerce application, not all API consumers will need the ability to place orders. Instead, you may allow the consumers to only request authorization to access order shipment statuses. In other words, scopes allow your application's users to limit the actions a third-party application can perform on their behalf. + +You may define your API's scopes using the `Passport::tokensCan` method in the `boot` method of your `AuthServiceProvider`. The `tokensCan` method accepts an array of scope names and scope descriptions. The scope description may be anything you wish and will be displayed to users on the authorization approval screen: + + use Laravel\Passport\Passport; + + Passport::tokensCan([ + 'place-orders' => 'Place orders', + 'check-status' => 'Check order status', + ]); + + +### Assigning Scopes To Tokens + +#### When Requesting Authorization Codes + +When requesting an access token using the authorization code grant, consumers should specify their desired scopes as the `scope` query string parameter. The `scope` parameter should be a space-delimited list of scopes: + + Route::get('/redirect', function () { + $query = http_build_query([ + 'client_id' => 'client-id', + 'redirect_uri' => 'http://example.com/callback', + 'response_type' => 'code', + 'scope' => 'place-orders check-status', + ]); + + return redirect('http://your-app.com/oauth/authorize?'.$query); + }); + +#### When Issuing Personal Access Tokens + +If you are issuing personal access tokens using the `User` model's `createToken` method, you may pass the array of desired scopes as the second argument to the method: + + $token = $user->createToken('My Token', ['place-orders'])->accessToken; + + +### Checking Scopes + +Passport includes two middleware that may be used to verify that an incoming request is authenticated with a token that has been granted a given scope. To get started, add the following middleware to the `$routeMiddleware` property of your `app/Http/Kernel.php` file: + + 'scopes' => \Laravel\Passport\Http\Middleware\CheckScopes::class, + 'scope' => \Laravel\Passport\Http\Middleware\CheckForAnyScope::class, + +#### Check For All Scopes + +The `scopes` middleware may be assigned to a route to verify that the incoming request's access token has *all* of the listed scopes: + + Route::get('/orders', function () { + // Access token has both "check-status" and "place-orders" scopes... + })->middleware('scopes:check-status,place-orders'); + +#### Check For Any Scopes + +The `scope` middleware may be assigned to a route to verify that the incoming request's access token has *at least one* of the listed scopes: + + Route::get('/orders', function () { + // Access token has either "check-status" or "place-orders" scope... + })->middleware('scope:check-status,place-orders'); + +#### Checking Scopes On A Token Instance + +Once an access token authenticated request has entered your application, you may still check if the token has a given scope using the `tokenCan` method on the authenticated `User` instance: + + use Illuminate\Http\Request; + + Route::get('/orders', function (Request $request) { + if ($request->user()->tokenCan('place-orders')) { + // + } + }); + + +## Consuming Your API With JavaScript + +When building an API, it can be extremely useful to be able to consume your own API from your JavaScript application. This approach to API development allows your own application to consume the same API that you are sharing with the world. The same API may be consumed by your web application, mobile applications, third-party applications, and any SDKs that you may publish on various package managers. + +Typically, if you want to consume your API from your JavaScript application, you would need to manually send an access token to the application and pass it with each request to your application. However, Passport includes a middleware that can handle this for you. All you need to do is add the `CreateFreshApiToken` middleware to your `web` middleware group: + + 'web' => [ + // Other middleware... + \Laravel\Passport\Http\Middleware\CreateFreshApiToken::class, + ], + +This Passport middleware will attach a `laravel_token` cookie to your outgoing responses. This cookie contains an encrypted JWT that Passport will use to authenticate API requests from your JavaScript application. Now, you may make requests to your application's API without explicitly passing an access token: + + axios.get('/user') + .then(response => { + console.log(response.data); + }); + +When using this method of authentication, Axios will automatically send the `X-CSRF-TOKEN` header. In addition, the default Laravel JavaScript scaffolding instructs Axios to send the `X-Requested-With` header: + + window.axios.defaults.headers.common = { + 'X-Requested-With': 'XMLHttpRequest', + }; + +> {note} If you are using a different JavaScript framework, you should make sure it is configured to send the `X-CSRF-TOKEN` and `X-Requested-With` headers with every outgoing request. + + + +## Events + +Passport raises events when issuing access tokens and refresh tokens. You may use these events to prune or revoke other access tokens in your database. You may attach listeners to these events in your application's `EventServiceProvider`: + +```php +/** + * The event listener mappings for the application. + * + * @var array + */ +protected $listen = [ + 'Laravel\Passport\Events\AccessTokenCreated' => [ + 'App\Listeners\RevokeOldTokens', + ], + + 'Laravel\Passport\Events\RefreshTokenCreated' => [ + 'App\Listeners\PruneOldTokens', + ], +]; +``` diff --git a/passwords.md b/passwords.md new file mode 100644 index 0000000..0a8beee --- /dev/null +++ b/passwords.md @@ -0,0 +1,97 @@ +# Resetting Passwords + +- [Introduction](#introduction) +- [Database Considerations](#resetting-database) +- [Routing](#resetting-routing) +- [Views](#resetting-views) +- [After Resetting Passwords](#after-resetting-passwords) +- [Customization](#password-customization) + + +## Introduction + +> {tip} **Want to get started fast?** Just run `php artisan make:auth` in a fresh Laravel application and navigate your browser to `http://your-app.dev/register` or any other URL that is assigned to your application. This single command will take care of scaffolding your entire authentication system, including resetting passwords! + +Most web applications provide a way for users to reset their forgotten passwords. Rather than forcing you to re-implement this on each application, Laravel provides convenient methods for sending password reminders and performing password resets. + +> {note} Before using the password reset features of Laravel, your user must use the `Illuminate\Notifications\Notifiable` trait. + + +## Database Considerations + +To get started, verify that your `App\User` model implements the `Illuminate\Contracts\Auth\CanResetPassword` contract. Of course, the `App\User` model included with the framework already implements this interface, and uses the `Illuminate\Auth\Passwords\CanResetPassword` trait to include the methods needed to implement the interface. + +#### Generating The Reset Token Table Migration + +Next, a table must be created to store the password reset tokens. The migration for this table is included with Laravel out of the box, and resides in the `database/migrations` directory. So, all you need to do is run your database migrations: + + php artisan migrate + + +## Routing + +Laravel includes `Auth\ForgotPasswordController` and `Auth\ResetPasswordController` classes that contains the logic necessary to e-mail password reset links and reset user passwords. All of the routes needed to perform password resets may be generated using the `make:auth` Artisan command: + + php artisan make:auth + + +## Views + +Again, Laravel will generate all of the necessary views for password reset when the `make:auth` command is executed. These views are placed in `resources/views/auth/passwords`. You are free to customize them as needed for your application. + + +## After Resetting Passwords + +Once you have defined the routes and views to reset your user's passwords, you may simply access the route in your browser at `/password/reset`. The `ForgotPasswordController` included with the framework already includes the logic to send the password reset link e-mails, while the `ResetPasswordController` includes the logic to reset user passwords. + +After a password is reset, the user will automatically be logged into the application and redirected to `/home`. You can customize the post password reset redirect location by defining a `redirectTo` property on the `ResetPasswordController`: + + protected $redirectTo = '/dashboard'; + +> {note} By default, password reset tokens expire after one hour. You may change this via the password reset `expire` option in your `config/auth.php` file. + + +## Customization + +#### Authentication Guard Customization + +In your `auth.php` configuration file, you may configure multiple "guards", which may be used to define authentication behavior for multiple user tables. You can customize the included `ResetPasswordController` to use the guard of your choice by overriding the `guard` method on the controller. This method should return a guard instance: + + use Illuminate\Support\Facades\Auth; + + protected function guard() + { + return Auth::guard('guard-name'); + } + +#### Password Broker Customization + +In your `auth.php` configuration file, you may configure multiple password "brokers", which may be used to reset passwords on multiple user tables. You can customize the included `ForgotPasswordController` and `ResetPasswordController` to use the broker of your choice by overriding the `broker` method: + + use Illuminate\Support\Facades\Password; + + /** + * Get the broker to be used during password reset. + * + * @return PasswordBroker + */ + protected function broker() + { + return Password::broker('name'); + } + +#### Reset Email Customization + +You may easily modify the notification class used to send the password reset link to the user. To get started, override the `sendPasswordResetNotification` method on your `User` model. Within this method, you may send the notification using any notification class you choose. The password reset `$token` is the first argument received by the method: + + /** + * Send the password reset notification. + * + * @param string $token + * @return void + */ + public function sendPasswordResetNotification($token) + { + $this->notify(new ResetPasswordNotification($token)); + } + diff --git a/providers.md b/providers.md new file mode 100644 index 0000000..1f59fa0 --- /dev/null +++ b/providers.md @@ -0,0 +1,160 @@ +# Service Providers + +- [Introduction](#introduction) +- [Writing Service Providers](#writing-service-providers) + - [The Register Method](#the-register-method) + - [The Boot Method](#the-boot-method) +- [Registering Providers](#registering-providers) +- [Deferred Providers](#deferred-providers) + + +## Introduction + +Service providers are the central place of all Laravel application bootstrapping. Your own application, as well as all of Laravel's core services are bootstrapped via service providers. + +But, what do we mean by "bootstrapped"? In general, we mean **registering** things, including registering service container bindings, event listeners, middleware, and even routes. Service providers are the central place to configure your application. + +If you open the `config/app.php` file included with Laravel, you will see a `providers` array. These are all of the service provider classes that will be loaded for your application. Of course, many of these are "deferred" providers, meaning they will not be loaded on every request, but only when the services they provide are actually needed. + +In this overview you will learn how to write your own service providers and register them with your Laravel application. + + +## Writing Service Providers + +All service providers extend the `Illuminate\Support\ServiceProvider` class. Most service providers contain a `register` and a `boot` method. Within the `register` method, you should **only bind things into the [service container](/docs/{{version}}/container)**. You should never attempt to register any event listeners, routes, or any other piece of functionality within the `register` method. + +The Artisan CLI can generate a new provider via the `make:provider` command: + + php artisan make:provider RiakServiceProvider + + +### The Register Method + +As mentioned previously, within the `register` method, you should only bind things into the [service container](/docs/{{version}}/container). You should never attempt to register any event listeners, routes, or any other piece of functionality within the `register` method. Otherwise, you may accidentally use a service that is provided by a service provider which has not loaded yet. + +Let's take a look at a basic service provider. Within any of your service provider methods, you always have access to the `$app` property which provides access to the service container: + + app->singleton(Connection::class, function ($app) { + return new Connection(config('riak')); + }); + } + } + +This service provider only defines a `register` method, and uses that method to define an implementation of `Riak\Connection` in the service container. If you don't understand how the service container works, check out [its documentation](/docs/{{version}}/container). + + +### The Boot Method + +So, what if we need to register a view composer within our service provider? This should be done within the `boot` method. **This method is called after all other service providers have been registered**, meaning you have access to all other services that have been registered by the framework: + + composer('view', function () { + // + }); + } + } + +#### Boot Method Dependency Injection + +You may type-hint dependencies for your service provider's `boot` method. The [service container](/docs/{{version}}/container) will automatically inject any dependencies you need: + + use Illuminate\Contracts\Routing\ResponseFactory; + + public function boot(ResponseFactory $response) + { + $response->macro('caps', function ($value) { + // + }); + } + + +## Registering Providers + +All service providers are registered in the `config/app.php` configuration file. This file contains a `providers` array where you can list the class names of your service providers. By default, a set of Laravel core service providers are listed in this array. These providers bootstrap the core Laravel components, such as the mailer, queue, cache, and others. + +To register your provider, simply add it to the array: + + 'providers' => [ + // Other Service Providers + + App\Providers\ComposerServiceProvider::class, + ], + + +## Deferred Providers + +If your provider is **only** registering bindings in the [service container](/docs/{{version}}/container), you may choose to defer its registration until one of the registered bindings is actually needed. Deferring the loading of such a provider will improve the performance of your application, since it is not loaded from the filesystem on every request. + +Laravel compiles and stores a list of all of the services supplied by deferred service providers, along with the name of its service provider class. Then, only when you attempt to resolve one of these services does Laravel load the service provider. + +To defer the loading of a provider, set the `defer` property to `true` and define a `provides` method. The `provides` method should return the service container bindings registered by the provider: + + app->singleton(Connection::class, function ($app) { + return new Connection($app['config']['riak']); + }); + } + + /** + * Get the services provided by the provider. + * + * @return array + */ + public function provides() + { + return [Connection::class]; + } + + } diff --git a/queries.md b/queries.md old mode 100755 new mode 100644 index 3d1cb11..0458680 --- a/queries.md +++ b/queries.md @@ -1,318 +1,582 @@ -# Query Builder +# Database: Query Builder - [Introduction](#introduction) +- [Retrieving Results](#retrieving-results) + - [Chunking Results](#chunking-results) + - [Aggregates](#aggregates) - [Selects](#selects) -- [Joins](#joins) -- [Advanced Wheres](#advanced-wheres) -- [Aggregates](#aggregates) - [Raw Expressions](#raw-expressions) +- [Joins](#joins) +- [Unions](#unions) +- [Where Clauses](#where-clauses) + - [Parameter Grouping](#parameter-grouping) + - [Where Exists Clauses](#where-exists-clauses) + - [JSON Where Clauses](#json-where-clauses) +- [Ordering, Grouping, Limit, & Offset](#ordering-grouping-limit-and-offset) +- [Conditional Clauses](#conditional-clauses) - [Inserts](#inserts) - [Updates](#updates) + - [Updating JSON Columns](#updating-json-columns) + - [Increment & Decrement](#increment-and-decrement) - [Deletes](#deletes) -- [Unions](#unions) - [Pessimistic Locking](#pessimistic-locking) -- [Caching Queries](#caching-queries) ## Introduction -The database query builder provides a convenient, fluent interface to creating and running database queries. It can be used to perform most database operations in your application, and works on all supported database systems. +Laravel's database query builder provides a convenient, fluent interface to creating and running database queries. It can be used to perform most database operations in your application and works on all supported database systems. -> **Note:** The Laravel query builder uses PDO parameter binding throughout to protect your application against SQL injection attacks. There is no need to clean strings being passed as bindings. +The Laravel query builder uses PDO parameter binding to protect your application against SQL injection attacks. There is no need to clean strings being passed as bindings. - -## Selects + +## Retrieving Results #### Retrieving All Rows From A Table - $users = DB::table('users')->get(); +You may use the `table` method on the `DB` facade to begin a query. The `table` method returns a fluent query builder instance for the given table, allowing you to chain more constraints onto the query and then finally get the results using the `get` method: + + name); - } + use Illuminate\Support\Facades\DB; + use App\Http\Controllers\Controller; -#### Retrieving A Single Row From A Table + class UserController extends Controller + { + /** + * Show a list of all of the application's users. + * + * @return Response + */ + public function index() + { + $users = DB::table('users')->get(); - $user = DB::table('users')->where('name', 'John')->first(); + return view('user.index', ['users' => $users]); + } + } - var_dump($user->name); +The `get` method returns an `Illuminate\Support\Collection` containing the results where each result is an instance of the PHP `StdClass` object. You may access each column's value by accessing the column as a property of the object: -#### Retrieving A Single Column From A Row + foreach ($users as $user) { + echo $user->name; + } - $name = DB::table('users')->where('name', 'John')->pluck('name'); +#### Retrieving A Single Row / Column From A Table + +If you just need to retrieve a single row from the database table, you may use the `first` method. This method will return a single `StdClass` object: + + $user = DB::table('users')->where('name', 'John')->first(); + + echo $user->name; + +If you don't even need an entire row, you may extract a single value from a record using the `value` method. This method will return the value of the column directly: + + $email = DB::table('users')->where('name', 'John')->value('email'); #### Retrieving A List Of Column Values - $roles = DB::table('roles')->lists('title'); +If you would like to retrieve a Collection containing the values of a single column, you may use the `pluck` method. In this example, we'll retrieve a Collection of role titles: -This method will return an array of role titles. You may also specify a custom key column for the returned array: + $titles = DB::table('roles')->pluck('title'); - $roles = DB::table('roles')->lists('title', 'name'); + foreach ($titles as $title) { + echo $title; + } -#### Specifying A Select Clause + You may also specify a custom key column for the returned Collection: - $users = DB::table('users')->select('name', 'email')->get(); + $roles = DB::table('roles')->pluck('title', 'name'); - $users = DB::table('users')->distinct()->get(); + foreach ($roles as $name => $title) { + echo $title; + } - $users = DB::table('users')->select('name as user_name')->get(); + +### Chunking Results -#### Adding A Select Clause To An Existing Query +If you need to work with thousands of database records, consider using the `chunk` method. This method retrieves a small chunk of the results at a time and feeds each chunk into a `Closure` for processing. This method is very useful for writing [Artisan commands](/docs/{{version}}/artisan) that process thousands of records. For example, let's work with the entire `users` table in chunks of 100 records at a time: - $query = DB::table('users')->select('name'); + DB::table('users')->orderBy('id')->chunk(100, function ($users) { + foreach ($users as $user) { + // + } + }); - $users = $query->addSelect('age')->get(); +You may stop further chunks from being processed by returning `false` from the `Closure`: -#### Using Where Operators + DB::table('users')->orderBy('id')->chunk(100, function ($users) { + // Process the records... - $users = DB::table('users')->where('votes', '>', 100)->get(); + return false; + }); -#### Or Statements + +### Aggregates + +The query builder also provides a variety of aggregate methods such as `count`, `max`, `min`, `avg`, and `sum`. You may call any of these methods after constructing your query: - $users = DB::table('users') - ->where('votes', '>', 100) - ->orWhere('name', 'John') - ->get(); + $users = DB::table('users')->count(); -#### Using Where Between + $price = DB::table('orders')->max('price'); - $users = DB::table('users') - ->whereBetween('votes', array(1, 100))->get(); +Of course, you may combine these methods with other clauses: -#### Using Where Not Between + $price = DB::table('orders') + ->where('finalized', 1) + ->avg('price'); - $users = DB::table('users') - ->whereNotBetween('votes', array(1, 100))->get(); + +## Selects -#### Using Where In With An Array +#### Specifying A Select Clause - $users = DB::table('users') - ->whereIn('id', array(1, 2, 3))->get(); +Of course, you may not always want to select all columns from a database table. Using the `select` method, you can specify a custom `select` clause for the query: - $users = DB::table('users') - ->whereNotIn('id', array(1, 2, 3))->get(); + $users = DB::table('users')->select('name', 'email as user_email')->get(); -#### Using Where Null To Find Records With Unset Values +The `distinct` method allows you to force the query to return distinct results: - $users = DB::table('users') - ->whereNull('updated_at')->get(); + $users = DB::table('users')->distinct()->get(); -#### Order By, Group By, And Having +If you already have a query builder instance and you wish to add a column to its existing select clause, you may use the `addSelect` method: - $users = DB::table('users') - ->orderBy('name', 'desc') - ->groupBy('count') - ->having('count', '>', 100) - ->get(); + $query = DB::table('users')->select('name'); -#### Offset & Limit + $users = $query->addSelect('age')->get(); - $users = DB::table('users')->skip(10)->take(5)->get(); + +## Raw Expressions + +Sometimes you may need to use a raw expression in a query. These expressions will be injected into the query as strings, so be careful not to create any SQL injection points! To create a raw expression, you may use the `DB::raw` method: + + $users = DB::table('users') + ->select(DB::raw('count(*) as user_count, status')) + ->where('status', '<>', 1) + ->groupBy('status') + ->get(); ## Joins -The query builder may also be used to write join statements. Take a look at the following examples: +#### Inner Join Clause + +The query builder may also be used to write join statements. To perform a basic "inner join", you may use the `join` method on a query builder instance. The first argument passed to the `join` method is the name of the table you need to join to, while the remaining arguments specify the column constraints for the join. Of course, as you can see, you can join to multiple tables in a single query: + + $users = DB::table('users') + ->join('contacts', 'users.id', '=', 'contacts.user_id') + ->join('orders', 'users.id', '=', 'orders.user_id') + ->select('users.*', 'contacts.phone', 'orders.price') + ->get(); + +#### Left Join Clause + +If you would like to perform a "left join" instead of an "inner join", use the `leftJoin` method. The `leftJoin` method has the same signature as the `join` method: + + $users = DB::table('users') + ->leftJoin('posts', 'users.id', '=', 'posts.user_id') + ->get(); -#### Basic Join Statement +#### Cross Join Clause - DB::table('users') - ->join('contacts', 'users.id', '=', 'contacts.user_id') - ->join('orders', 'users.id', '=', 'orders.user_id') - ->select('users.id', 'contacts.phone', 'orders.price') - ->get(); +To perform a "cross join" use the `crossJoin` method with the name of the table you wish to cross join to. Cross joins generate a cartesian product between the first table and the joined table: -#### Left Join Statement + $users = DB::table('sizes') + ->crossJoin('colours') + ->get(); - DB::table('users') - ->leftJoin('posts', 'users.id', '=', 'posts.user_id') - ->get(); +#### Advanced Join Clauses -You may also specify more advanced join clauses: +You may also specify more advanced join clauses. To get started, pass a `Closure` as the second argument into the `join` method. The `Closure` will receive a `JoinClause` object which allows you to specify constraints on the `join` clause: - DB::table('users') - ->join('contacts', function($join) - { - $join->on('users.id', '=', 'contacts.user_id')->orOn(...); - }) - ->get(); + DB::table('users') + ->join('contacts', function ($join) { + $join->on('users.id', '=', 'contacts.user_id')->orOn(...); + }) + ->get(); If you would like to use a "where" style clause on your joins, you may use the `where` and `orWhere` methods on a join. Instead of comparing two columns, these methods will compare the column against a value: - DB::table('users') - ->join('contacts', function($join) - { - $join->on('users.id', '=', 'contacts.user_id') - ->where('contacts.user_id', '>', 5); - }) - ->get(); + DB::table('users') + ->join('contacts', function ($join) { + $join->on('users.id', '=', 'contacts.user_id') + ->where('contacts.user_id', '>', 5); + }) + ->get(); - -## Advanced Wheres + +## Unions -#### Parameter Grouping +The query builder also provides a quick way to "union" two queries together. For example, you may create an initial query and use the `union` method to union it with a second query: -Sometimes you may need to create more advanced where clauses such as "where exists" or nested parameter groupings. The Laravel query builder can handle these as well: + $first = DB::table('users') + ->whereNull('first_name'); - DB::table('users') - ->where('name', '=', 'John') - ->orWhere(function($query) - { - $query->where('votes', '>', 100) - ->where('title', '<>', 'Admin'); - }) - ->get(); + $users = DB::table('users') + ->whereNull('last_name') + ->union($first) + ->get(); -The query above will produce the following SQL: +> {tip} The `unionAll` method is also available and has the same method signature as `union`. + + +## Where Clauses + +#### Simple Where Clauses + +You may use the `where` method on a query builder instance to add `where` clauses to the query. The most basic call to `where` requires three arguments. The first argument is the name of the column. The second argument is an operator, which can be any of the database's supported operators. Finally, the third argument is the value to evaluate against the column. + +For example, here is a query that verifies the value of the "votes" column is equal to 100: + + $users = DB::table('users')->where('votes', '=', 100)->get(); + +For convenience, if you simply want to verify that a column is equal to a given value, you may pass the value directly as the second argument to the `where` method: + + $users = DB::table('users')->where('votes', 100)->get(); + +Of course, you may use a variety of other operators when writing a `where` clause: + + $users = DB::table('users') + ->where('votes', '>=', 100) + ->get(); + + $users = DB::table('users') + ->where('votes', '<>', 100) + ->get(); + + $users = DB::table('users') + ->where('name', 'like', 'T%') + ->get(); + +You may also pass an array of conditions to the `where` function: + + $users = DB::table('users')->where([ + ['status', '=', '1'], + ['subscribed', '<>', '1'], + ])->get(); + +#### Or Statements + +You may chain where constraints together as well as add `or` clauses to the query. The `orWhere` method accepts the same arguments as the `where` method: + + $users = DB::table('users') + ->where('votes', '>', 100) + ->orWhere('name', 'John') + ->get(); + +#### Additional Where Clauses + +**whereBetween** + +The `whereBetween` method verifies that a column's value is between two values: + + $users = DB::table('users') + ->whereBetween('votes', [1, 100])->get(); + +**whereNotBetween** + +The `whereNotBetween` method verifies that a column's value lies outside of two values: + + $users = DB::table('users') + ->whereNotBetween('votes', [1, 100]) + ->get(); + +**whereIn / whereNotIn** + +The `whereIn` method verifies that a given column's value is contained within the given array: - select * from users where name = 'John' or (votes > 100 and title <> 'Admin') + $users = DB::table('users') + ->whereIn('id', [1, 2, 3]) + ->get(); -#### Exists Statements +The `whereNotIn` method verifies that the given column's value is **not** contained in the given array: - DB::table('users') - ->whereExists(function($query) - { - $query->select(DB::raw(1)) - ->from('orders') - ->whereRaw('orders.user_id = users.id'); - }) - ->get(); + $users = DB::table('users') + ->whereNotIn('id', [1, 2, 3]) + ->get(); + +**whereNull / whereNotNull** + +The `whereNull` method verifies that the value of the given column is `NULL`: + + $users = DB::table('users') + ->whereNull('updated_at') + ->get(); + +The `whereNotNull` method verifies that the column's value is not `NULL`: + + $users = DB::table('users') + ->whereNotNull('updated_at') + ->get(); + +**whereDate / whereMonth / whereDay / whereYear** + +The `whereDate` method may be used to compare a column's value against a date: + + $users = DB::table('users') + ->whereDate('created_at', '2016-12-31') + ->get(); + +The `whereMonth` method may be used to compare a column's value against a specific month of a year: + + $users = DB::table('users') + ->whereMonth('created_at', '12') + ->get(); + +The `whereDay` method may be used to compare a column's value against a specific day of a month: + + $users = DB::table('users') + ->whereDay('created_at', '31') + ->get(); + +The `whereYear` method may be used to compare a column's value against a specific year: + + $users = DB::table('users') + ->whereYear('created_at', '2016') + ->get(); + +**whereColumn** + +The `whereColumn` method may be used to verify that two columns are equal: + + $users = DB::table('users') + ->whereColumn('first_name', 'last_name') + ->get(); + +You may also pass a comparison operator to the method: + + $users = DB::table('users') + ->whereColumn('updated_at', '>', 'created_at') + ->get(); + +The `whereColumn` method can also be passed an array of multiple conditions. These conditions will be joined using the `and` operator: + + $users = DB::table('users') + ->whereColumn([ + ['first_name', '=', 'last_name'], + ['updated_at', '>', 'created_at'] + ])->get(); + + +### Parameter Grouping + +Sometimes you may need to create more advanced where clauses such as "where exists" clauses or nested parameter groupings. The Laravel query builder can handle these as well. To get started, let's look at an example of grouping constraints within parenthesis: + + DB::table('users') + ->where('name', '=', 'John') + ->orWhere(function ($query) { + $query->where('votes', '>', 100) + ->where('title', '<>', 'Admin'); + }) + ->get(); + +As you can see, passing a `Closure` into the `orWhere` method instructs the query builder to begin a constraint group. The `Closure` will receive a query builder instance which you can use to set the constraints that should be contained within the parenthesis group. The example above will produce the following SQL: + + select * from users where name = 'John' or (votes > 100 and title <> 'Admin') + + +### Where Exists Clauses + +The `whereExists` method allows you to write `where exists` SQL clauses. The `whereExists` method accepts a `Closure` argument, which will receive a query builder instance allowing you to define the query that should be placed inside of the "exists" clause: + + DB::table('users') + ->whereExists(function ($query) { + $query->select(DB::raw(1)) + ->from('orders') + ->whereRaw('orders.user_id = users.id'); + }) + ->get(); The query above will produce the following SQL: - select * from users - where exists ( - select 1 from orders where orders.user_id = users.id - ) + select * from users + where exists ( + select 1 from orders where orders.user_id = users.id + ) - -## Aggregates + +### JSON Where Clauses -The query builder also provides a variety of aggregate methods, such as `count`, `max`, `min`, `avg`, and `sum`. +Laravel also supports querying JSON column types on databases that provide support for JSON column types. Currently, this includes MySQL 5.7 and Postgres. To query a JSON column, use the `->` operator: -#### Using Aggregate Methods + $users = DB::table('users') + ->where('options->language', 'en') + ->get(); - $users = DB::table('users')->count(); + $users = DB::table('users') + ->where('preferences->dining->meal', 'salad') + ->get(); - $price = DB::table('orders')->max('price'); + +## Ordering, Grouping, Limit, & Offset - $price = DB::table('orders')->min('price'); +#### orderBy - $price = DB::table('orders')->avg('price'); +The `orderBy` method allows you to sort the result of the query by a given column. The first argument to the `orderBy` method should be the column you wish to sort by, while the second argument controls the direction of the sort and may be either `asc` or `desc`: - $total = DB::table('users')->sum('votes'); + $users = DB::table('users') + ->orderBy('name', 'desc') + ->get(); - -## Raw Expressions +#### latest / oldest -Sometimes you may need to use a raw expression in a query. These expressions will be injected into the query as strings, so be careful not to create any SQL injection points! To create a raw expression, you may use the `DB::raw` method: +The `latest` and `oldest` methods allow you to easily order results by date. By default, result will be ordered by the `created_at` column. Or, you may pass the column name that you wish to sort by: + + $user = DB::table('users') + ->latest() + ->first(); + +#### inRandomOrder + +The `inRandomOrder` method may be used to sort the query results randomly. For example, you may use this method to fetch a random user: + + $randomUser = DB::table('users') + ->inRandomOrder() + ->first(); + +#### groupBy / having / havingRaw + +The `groupBy` and `having` methods may be used to group the query results. The `having` method's signature is similar to that of the `where` method: + + $users = DB::table('users') + ->groupBy('account_id') + ->having('account_id', '>', 100) + ->get(); + +The `havingRaw` method may be used to set a raw string as the value of the `having` clause. For example, we can find all of the departments with sales greater than $2,500: + + $users = DB::table('orders') + ->select('department', DB::raw('SUM(price) as total_sales')) + ->groupBy('department') + ->havingRaw('SUM(price) > 2500') + ->get(); + +#### skip / take + +To limit the number of results returned from the query, or to skip a given number of results in the query, you may use the `skip` and `take` methods: + + $users = DB::table('users')->skip(10)->take(5)->get(); -#### Using A Raw Expression +Alternatively, you may use the `limit` and `offset` methods: - $users = DB::table('users') - ->select(DB::raw('count(*) as user_count, status')) - ->where('status', '<>', 1) - ->groupBy('status') - ->get(); + $users = DB::table('users') + ->offset(10) + ->limit(5) + ->get(); -#### Incrementing or decrementing a value of a column + +## Conditional Clauses - DB::table('users')->increment('votes'); +Sometimes you may want clauses to apply to a query only when something else is true. For instance you may only want to apply a `where` statement if a given input value is present on the incoming request. You may accomplish this using the `when` method: - DB::table('users')->increment('votes', 5); + $role = $request->input('role'); - DB::table('users')->decrement('votes'); + $users = DB::table('users') + ->when($role, function ($query) use ($role) { + return $query->where('role_id', $role); + }) + ->get(); - DB::table('users')->decrement('votes', 5); -You may also specify additional columns to update: +The `when` method only executes the given Closure when the first parameter is `true`. If the first parameter is `false`, the Closure will not be executed. + +You may pass another Closure as the third parameter to the `when` method. This Closure will execute if the first parameter evaluates as `false`. To illustrate how this feature may be used, we will use it to configure the default sorting of a query: + + $sortBy = null; + + $users = DB::table('users') + ->when($sortBy, function ($query) use ($sortBy) { + return $query->orderBy($sortBy); + }, function ($query) { + return $query->orderBy('name'); + }) + ->get(); - DB::table('users')->increment('votes', 1, array('name' => 'John')); ## Inserts -#### Inserting Records Into A Table +The query builder also provides an `insert` method for inserting records into the database table. The `insert` method accepts an array of column names and values: - DB::table('users')->insert( - array('email' => 'john@example.com', 'votes' => 0) - ); + DB::table('users')->insert( + ['email' => 'john@example.com', 'votes' => 0] + ); -#### Inserting Records Into A Table With An Auto-Incrementing ID +You may even insert several records into the table with a single call to `insert` by passing an array of arrays. Each array represents a row to be inserted into the table: -If the table has an auto-incrementing id, use `insertGetId` to insert a record and retrieve the id: + DB::table('users')->insert([ + ['email' => 'taylor@example.com', 'votes' => 0], + ['email' => 'dayle@example.com', 'votes' => 0] + ]); - $id = DB::table('users')->insertGetId( - array('email' => 'john@example.com', 'votes' => 0) - ); +#### Auto-Incrementing IDs -> **Note:** When using PostgreSQL the insertGetId method expects the auto-incrementing column to be named "id". +If the table has an auto-incrementing id, use the `insertGetId` method to insert a record and then retrieve the ID: -#### Inserting Multiple Records Into A Table + $id = DB::table('users')->insertGetId( + ['email' => 'john@example.com', 'votes' => 0] + ); - DB::table('users')->insert(array( - array('email' => 'taylor@example.com', 'votes' => 0), - array('email' => 'dayle@example.com', 'votes' => 0), - )); +> {note} When using PostgreSQL the insertGetId method expects the auto-incrementing column to be named `id`. If you would like to retrieve the ID from a different "sequence", you may pass the sequence name as the second parameter to the `insertGetId` method. ## Updates -#### Updating Records In A Table +Of course, in addition to inserting records into the database, the query builder can also update existing records using the `update` method. The `update` method, like the `insert` method, accepts an array of column and value pairs containing the columns to be updated. You may constrain the `update` query using `where` clauses: - DB::table('users') - ->where('id', 1) - ->update(array('votes' => 1)); + DB::table('users') + ->where('id', 1) + ->update(['votes' => 1]); - -## Deletes - -#### Deleting Records In A Table + +### Updating JSON Columns - DB::table('users')->where('votes', '<', 100)->delete(); +When updating a JSON column, you should use `->` syntax to access the appropriate key in the JSON object. This operation is only supported on databases that support JSON columns: -#### Deleting All Records From A Table + DB::table('users') + ->where('id', 1) + ->update(['options->enabled' => true]); - DB::table('users')->delete(); + +### Increment & Decrement -#### Truncating A Table +The query builder also provides convenient methods for incrementing or decrementing the value of a given column. This is simply a shortcut, providing a more expressive and terse interface compared to manually writing the `update` statement. - DB::table('users')->truncate(); +Both of these methods accept at least one argument: the column to modify. A second argument may optionally be passed to control the amount by which the column should be incremented or decremented: - -## Unions + DB::table('users')->increment('votes'); -The query builder also provides a quick way to "union" two queries together: + DB::table('users')->increment('votes', 5); - $first = DB::table('users')->whereNull('first_name'); + DB::table('users')->decrement('votes'); - $users = DB::table('users')->whereNull('last_name')->union($first)->get(); + DB::table('users')->decrement('votes', 5); -The `unionAll` method is also available, and has the same method signature as `union`. +You may also specify additional columns to update during the operation: - -## Pessimistic Locking + DB::table('users')->increment('votes', 1, ['name' => 'John']); -The query builder includes a few functions to help you do "pessimistic locking" on your SELECT statements. + +## Deletes -To run the SELECT statement with a "shared lock", you may use the `sharedLock` method on a query: +The query builder may also be used to delete records from the table via the `delete` method. You may constrain `delete` statements by adding `where` clauses before calling the `delete` method: - DB::table('users')->where('votes', '>', 100)->sharedLock()->get(); + DB::table('users')->delete(); -To "lock for update" on a SELECT statement, you may use the `lockForUpdate` method on a query: + DB::table('users')->where('votes', '>', 100)->delete(); - DB::table('users')->where('votes', '>', 100)->lockForUpdate()->get(); +If you wish to truncate the entire table, which will remove all rows and reset the auto-incrementing ID to zero, you may use the `truncate` method: - -## Caching Queries + DB::table('users')->truncate(); -You may easily cache the results of a query using the `remember` method: + +## Pessimistic Locking - $users = DB::table('users')->remember(10)->get(); +The query builder also includes a few functions to help you do "pessimistic locking" on your `select` statements. To run the statement with a "shared lock", you may use the `sharedLock` method on a query. A shared lock prevents the selected rows from being modified until your transaction commits: -In this example, the results of the query will be cached for ten minutes. While the results are cached, the query will not be run against the database, and the results will be loaded from the default cache driver specified for your application. + DB::table('users')->where('votes', '>', 100)->sharedLock()->get(); -If you are using a [supported cache driver](cache#cache-tags.md), you can also add tags to the caches: +Alternatively, you may use the `lockForUpdate` method. A "for update" lock prevents the rows from being modified or from being selected with another shared lock: - $users = DB::table('users')->cacheTags(array('people', 'authors'))->remember(10)->get(); + DB::table('users')->where('votes', '>', 100)->lockForUpdate()->get(); diff --git a/queues.md b/queues.md old mode 100755 new mode 100644 index fd7234e..34123b6 --- a/queues.md +++ b/queues.md @@ -1,255 +1,628 @@ # Queues -- [Configuration](#configuration) -- [Basic Usage](#basic-usage) -- [Queueing Closures](#queueing-closures) -- [Running The Queue Listener](#running-the-queue-listener) -- [Daemon Queue Worker](#daemon-queue-worker) -- [Push Queues](#push-queues) -- [Failed Jobs](#failed-jobs) +- [Introduction](#introduction) + - [Connections Vs. Queues](#connections-vs-queues) + - [Driver Prerequisites](#driver-prerequisites) +- [Creating Jobs](#creating-jobs) + - [Generating Job Classes](#generating-job-classes) + - [Class Structure](#class-structure) +- [Dispatching Jobs](#dispatching-jobs) + - [Delayed Dispatching](#delayed-dispatching) + - [Customizing The Queue & Connection](#customizing-the-queue-and-connection) + - [Specifying Max Job Attempts / Timeout Values](#max-job-attempts-and-timeout) + - [Error Handling](#error-handling) +- [Running The Queue Worker](#running-the-queue-worker) + - [Queue Priorities](#queue-priorities) + - [Queue Workers & Deployment](#queue-workers-and-deployment) + - [Job Expirations & Timeouts](#job-expirations-and-timeouts) +- [Supervisor Configuration](#supervisor-configuration) +- [Dealing With Failed Jobs](#dealing-with-failed-jobs) + - [Cleaning Up After Failed Jobs](#cleaning-up-after-failed-jobs) + - [Failed Job Events](#failed-job-events) + - [Retrying Failed Jobs](#retrying-failed-jobs) +- [Job Events](#job-events) - -## Configuration + +## Introduction -The Laravel Queue component provides a unified API across a variety of different queue services. Queues allow you to defer the processing of a time consuming task, such as sending an e-mail, until a later time, thus drastically speeding up the web requests to your application. +Laravel queues provide a unified API across a variety of different queue backends, such as Beanstalk, Amazon SQS, Redis, or even a relational database. Queues allow you to defer the processing of a time consuming task, such as sending an email, until a later time. Deferring these time consuming tasks drastically speeds up web requests to your application. -The queue configuration file is stored in `app/config/queue.php`. In this file you will find connection configurations for each of the queue drivers that are included with the framework, which includes a [Beanstalkd](http://kr.github.com/beanstalkd), [IronMQ](http://iron.io), [Amazon SQS](http://aws.amazon.com/sqs), [Redis](http://redis.io), and synchronous (for local use) driver. +The queue configuration file is stored in `config/queue.php`. In this file you will find connection configurations for each of the queue drivers that are included with the framework, which includes a database, [Beanstalkd](https://kr.github.io/beanstalkd/), [Amazon SQS](https://aws.amazon.com/sqs/), [Redis](http://redis.io), and a synchronous driver that will execute jobs immediately (for local use). A `null` queue driver is also included which simply discards queued jobs. + + +### Connections Vs. Queues + +Before getting started with Laravel queues, it is important to understand the distinction between "connections" and "queues". In your `config/queue.php` configuration file, there is a `connections` configuration option. This option defines a particular connection to a backend service such as Amazon SQS, Beanstalk, or Redis. However, any given queue connection may have multiple "queues" which may be thought of as different stacks or piles of queued jobs. + +Note that each connection configuration example in the `queue` configuration file contains a `queue` attribute. This is the default queue that jobs will be dispatched to when they are sent to a given connection. In other words, if you dispatch a job without explicitly defining which queue it should be dispatched to, the job will be placed on the queue that is defined in the `queue` attribute of the connection configuration: + + // This job is sent to the default queue... + dispatch(new Job); + + // This job is sent to the "emails" queue... + dispatch((new Job)->onQueue('emails')); + +Some applications may not need to ever push jobs onto multiple queues, instead preferring to have one simple queue. However, pushing jobs to multiple queues can be especially useful for applications that wish to prioritize or segment how jobs are processed, since the Laravel queue worker allows you to specify which queues it should process by priority. For example, if you push jobs to a `high` queue, you may run a worker that gives them higher processing priority: + + php artisan queue:work --queue=high,default + + +### Driver Prerequisites + +#### Database + +In order to use the `database` queue driver, you will need a database table to hold the jobs. To generate a migration that creates this table, run the `queue:table` Artisan command. Once the migration has been created, you may migrate your database using the `migrate` command: + + php artisan queue:table + + php artisan migrate + +#### Redis + +In order to use the `redis` queue driver, you should configure a Redis database connection in your `config/database.php` configuration file. + +If your Redis queue connection uses a Redis Cluster, your queue names must contain a [key hash tag](https://redis.io/topics/cluster-spec#keys-hash-tags). This is required in order to ensure all of the Redis keys for a given queue are placed into the same hash slot: + + 'redis' => [ + 'driver' => 'redis', + 'connection' => 'default', + 'queue' => '{default}', + 'retry_after' => 90, + ], + +#### Other Driver Prerequisites The following dependencies are needed for the listed queue drivers: -- Beanstalkd: `pda/pheanstalk` -- Amazon SQS: `aws/aws-sdk-php` -- IronMQ: `iron-io/iron_mq` +
    +- Amazon SQS: `aws/aws-sdk-php ~3.0` +- Beanstalkd: `pda/pheanstalk ~3.0` +- Redis: `predis/predis ~1.0` +
    + + +## Creating Jobs + + +### Generating Job Classes + +By default, all of the queueable jobs for your application are stored in the `app/Jobs` directory. If the `app/Jobs` directory doesn't exist, it will be created when you run the `make:job` Artisan command. You may generate a new queued job using the Artisan CLI: + + php artisan make:job SendReminderEmail + +The generated class will implement the `Illuminate\Contracts\Queue\ShouldQueue` interface, indicating to Laravel that the job should be pushed onto the queue to run asynchronously. + + +### Class Structure + +Job classes are very simple, normally containing only a `handle` method which is called when the job is processed by the queue. To get started, let's take a look at an example job class. In this example, we'll pretend we manage a podcast publishing service and need to process the uploaded podcast files before they are published: + + podcast = $podcast; + } + + /** + * Execute the job. + * + * @param AudioProcessor $processor + * @return void + */ + public function handle(AudioProcessor $processor) + { + // Process uploaded podcast... + } + } + +In this example, note that we were able to pass an [Eloquent model](/docs/{{version}}/eloquent) directly into the queued job's constructor. Because of the `SerializesModels` trait that the job is using, Eloquent models will be gracefully serialized and unserialized when the job is processing. If your queued job accepts an Eloquent model in its constructor, only the identifier for the model will be serialized onto the queue. When the job is actually handled, the queue system will automatically re-retrieve the full model instance from the database. It's all totally transparent to your application and prevents issues that can arise from serializing full Eloquent model instances. + +The `handle` method is called when the job is processed by the queue. Note that we are able to type-hint dependencies on the `handle` method of the job. The Laravel [service container](/docs/{{version}}/container) automatically injects these dependencies. + +> {note} Binary data, such as raw image contents, should be passed through the `base64_encode` function before being passed to a queued job. Otherwise, the job may not properly serialize to JSON when being placed on the queue. + + +## Dispatching Jobs + +Once you have written your job class, you may dispatch it using the `dispatch` helper. The only argument you need to pass to the `dispatch` helper is an instance of the job: + + {tip} The `dispatch` helper provides the convenience of a short, globally available function, while also being extremely easy to test. Check out the Laravel [testing documentation](/docs/{{version}}/testing) to learn more. + + +### Delayed Dispatching + +If you would like to delay the execution of a queued job, you may use the `delay` method on your job instance. The `delay` method is provided by the `Illuminate\Bus\Queueable` trait, which is included by default on all generated job classes. For example, let's specify that a job should not be available for processing until 10 minutes after it has been dispatched: + + delay(Carbon::now()->addMinutes(10)); + + dispatch($job); + } + } + +> {note} The Amazon SQS queue service has a maximum delay time of 15 minutes. + + +### Customizing The Queue & Connection + +#### Dispatching To A Particular Queue + +By pushing jobs to different queues, you may "categorize" your queued jobs and even prioritize how many workers you assign to various queues. Keep in mind, this does not push jobs to different queue "connections" as defined by your queue configuration file, but only to specific queues within a single connection. To specify the queue, use the `onQueue` method on the job instance: + + onQueue('processing'); - -## Basic Usage + dispatch($job); + } + } -#### Pushing A Job Onto The Queue +#### Dispatching To A Particular Connection -To push a new job onto the queue, use the `Queue::push` method: +If you are working with multiple queue connections, you may specify which connection to push a job to. To specify the connection, use the `onConnection` method on the job instance: - Queue::push('SendEmail', array('message' => $message)); + onConnection('sqs'); - } + dispatch($job); + } + } -Notice the only method that is required is `fire`, which receives a `Job` instance as well as the array of `data` that was pushed onto the queue. +Of course, you may chain the `onConnection` and `onQueue` methods to specify the connection and the queue for a job: -#### Specifying A Custom Handler Method + $job = (new ProcessPodcast($podcast)) + ->onConnection('sqs') + ->onQueue('processing'); -If you want the job to use a method other than `fire`, you may specify the method when you push the job: + +### Specifying Max Job Attempts / Timeout Values - Queue::push('SendEmail@send', array('message' => $message)); +#### Max Attempts -#### Specifying The Queue / Tube For A Job +One approach to specifying the maximum number of times a job may be attempted is via the `--tries` switch on the Artisan command line: -You may also specify the queue / tube a job should be sent to: + php artisan queue:work --tries=3 - Queue::push('SendEmail@send', array('message' => $message), 'emails'); +However, you may take a more granular approach by defining the maximum number of attempts on the job class itself. If the maximum number of attempts is specified on the job, it will take precedence over the value provided on the command line: -#### Passing The Same Payload To Multiple Jobs + addMinutes(15); + php artisan queue:work --timeout=30 - Queue::later($date, 'SendEmail@send', array('message' => $message)); +However, you may also define the maximum number of seconds a job should be allowed to run on the job class itself. If the timeout is specified on the job, it will take precedence over any timeout specified on the command line: -In this example, we're using the [Carbon](https://github.com/briannesbitt/Carbon) date library to specify the delay we wish to assign to the job. Alternatively, you may pass the number of seconds you wish to delay as an integer. + +### Error Handling - $job->delete(); - } +If an exception is thrown while the job is being processed, the job will automatically be released back onto the queue so it may be attempted again. The job will continue to be released until it has been attempted the maximum number of times allowed by your application. The maximum number of attempts is defined by the `--tries` switch used on the `queue:work` Artisan command. Alternatively, the maximum number of attempts may be defined on the job class itself. More information on running the queue worker [can be found below](#running-the-queue-worker). -#### Releasing A Job Back Onto The Queue + +## Running The Queue Worker -If you wish to release a job back onto the queue, you may do so via the `release` method: +Laravel includes a queue worker that will process new jobs as they are pushed onto the queue. You may run the worker using the `queue:work` Artisan command. Note that once the `queue:work` command has started, it will continue to run until it is manually stopped or you close your terminal: - public function fire($job, $data) - { - // Process the job... + php artisan queue:work - $job->release(); - } +> {tip} To keep the `queue:work` process running permanently in the background, you should use a process monitor such as [Supervisor](#supervisor-configuration) to ensure that the queue worker does not stop running. -You may also specify the number of seconds to wait before the job is released: +Remember, queue workers are long-lived processes and store the booted application state in memory. As a result, they will not notice changes in your code base after they have been started. So, during your deployment process, be sure to [restart your queue workers](#queue-workers-and-deployment). - $job->release(5); +#### Specifying The Connection & Queue -#### Checking The Number Of Run Attempts +You may also specify which queue connection the worker should utilize. The connection name passed to the `work` command should correspond to one of the connections defined in your `config/queue.php` configuration file: -If an exception occurs while the job is being processed, it will automatically be released back onto the queue. You may check the number of attempts that have been made to run the job using the `attempts` method: + php artisan queue:work redis - if ($job->attempts() > 3) - { - // - } +You may customize your queue worker even further by only processing particular queues for a given connection. For example, if all of your emails are processed in an `emails` queue on your `redis` queue connection, you may issue the following command to start a worker that only processes only that queue: -#### Accessing The Job ID + php artisan queue:work redis --queue=emails -You may also access the job identifier: +#### Resource Considerations - $job->getJobId(); +Daemon queue workers do not "reboot" the framework before processing each job. Therefore, you should free any heavy resources after each job completes. For example, if you are doing image manipulation with the GD library, you should free the memory with `imagedestroy` when you are done. - -## Queueing Closures + +### Queue Priorities -You may also push a Closure onto the queue. This is very convenient for quick, simple tasks that need to be queued: +Sometimes you may wish to prioritize how your queues are processed. For example, in your `config/queue.php` you may set the default `queue` for your `redis` connection to `low`. However, occasionally you may wish to push a job to a `high` priority queue like so: -#### Pushing A Closure Onto The Queue + dispatch((new Job)->onQueue('high')); - Queue::push(function($job) use ($id) - { - Account::delete($id); +To start a worker that verifies that all of the `high` queue jobs are processed before continuing to any jobs on the `low` queue, pass a comma-delimited list of queue names to the `work` command: - $job->delete(); - }); + php artisan queue:work --queue=high,low -When using Iron.io [push queues](#push-queues), you should take extra precaution queueing Closures. The end-point that receives your queue messages should check for a token to verify that the request is actually from Iron.io. For example, your push queue end-point should be something like: `https://yourapp.com/queue/receive?token=SecretToken`. You may then check the value of the secret token in your application before marshaling the queue request. + +### Queue Workers & Deployment - -## Running The Queue Listener +Since queue workers are long-lived processes, they will not pick up changes to your code without being restarted. So, the simplest way to deploy an application using queue workers is to restart the workers during your deployment process. You may gracefully restart all of the workers by issuing the `queue:restart` command: -Laravel includes an Artisan task that will run new jobs as they are pushed onto the queue. You may run this task using the `queue:listen` command: + php artisan queue:restart -#### Starting The Queue Listener +This command will instruct all queue workers to gracefully "die" after they finish processing their current job so that no existing jobs are lost. Since the queue workers will die when the `queue:restart` command is executed, you should be running a process manager such as [Supervisor](#supervisor-configuration) to automatically restart the queue workers. - php artisan queue:listen + +### Job Expirations & Timeouts -You may also specify which queue connection the listener should utilize: +#### Job Expiration - php artisan queue:listen connection +In your `config/queue.php` configuration file, each queue connection defines a `retry_after` option. This option specifies how many seconds the queue connection should wait before retrying a job that is being processed. For example, if the value of `retry_after` is set to `90`, the job will be released back onto the queue if it has been processing for 90 seconds without being deleted. Typically, you should set the `retry_after` value to the maximum number of seconds your jobs should reasonably take to complete processing. -Note that once this task has started, it will continue to run until it is manually stopped. You may use a process monitor such as [Supervisor](http://supervisord.org/) to ensure that the queue listener does not stop running. +> {note} The only queue connection which does not contain a `retry_after` value is Amazon SQS. SQS will retry the job based on the [Default Visibility Timeout](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/AboutVT.html) which is managed within the AWS console. -You may pass a comma-delimited list of queue connections to the `listen` command to set queue priorities: +#### Worker Timeouts - php artisan queue:listen --queue=high,low +The `queue:work` Artisan command exposes a `--timeout` option. The `--timeout` option specifies how long the Laravel queue master process will wait before killing off a child queue worker that is processing a job. Sometimes a child queue process can become "frozen" for various reasons, such as an external HTTP call that is not responding. The `--timeout` option removes frozen processes that have exceeded that specified time limit: -In this example, jobs on the `high-connection` will always be processed before moving onto jobs from the `low-connection`. + php artisan queue:work --timeout=60 -#### Specifying The Job Timeout Parameter +The `retry_after` configuration option and the `--timeout` CLI option are different, but work together to ensure that jobs are not lost and that jobs are only successfully processed once. -You may also set the length of time (in seconds) each job should be allowed to run: +> {note} The `--timeout` value should always be at least several seconds shorter than your `retry_after` configuration value. This will ensure that a worker processing a given job is always killed before the job is retried. If your `--timeout` option is longer than your `retry_after` configuration value, your jobs may be processed twice. - php artisan queue:listen --timeout=60 +#### Worker Sleep Duration -#### Specifying Queue Sleep Duration +When jobs are available on the queue, the worker will keep processing jobs with no delay in between them. However, the `sleep` option determines how long the worker will "sleep" if there are no new jobs available: -In addition, you may specify the number of seconds to wait before polling for new jobs: + php artisan queue:work --sleep=3 - php artisan queue:listen --sleep=5 + +## Supervisor Configuration -Note that the queue only "sleeps" if no jobs are on the queue. If more jobs are available, the queue will continue to work them without sleeping. +#### Installing Supervisor -#### Processing The First Job On The Queue +Supervisor is a process monitor for the Linux operating system, and will automatically restart your `queue:work` process if it fails. To install Supervisor on Ubuntu, you may use the following command: -To process only the first job on the queue, you may use the `queue:work` command: + sudo apt-get install supervisor - php artisan queue:work +> {tip} If configuring Supervisor yourself sounds overwhelming, consider using [Laravel Forge](https://forge.laravel.com), which will automatically install and configure Supervisor for your Laravel projects. - -## Daemon Queue Workers +#### Configuring Supervisor -The `queue:work` also includes a `--daemon` option for forcing the queue worker to continue processing jobs without ever re-booting the framework. This results in a significant reduction of CPU usage when compared to the `queue:listen` command, but at the added complexity of needing to drain the queues of currently executing jobs during your deployments. +Supervisor configuration files are typically stored in the `/etc/supervisor/conf.d` directory. Within this directory, you may create any number of configuration files that instruct supervisor how your processes should be monitored. For example, let's create a `laravel-worker.conf` file that starts and monitors a `queue:work` process: -To start a queue worker in daemon mode, use the `--daemon` flag: + [program:laravel-worker] + process_name=%(program_name)s_%(process_num)02d + command=php /home/forge/app.com/artisan queue:work sqs --sleep=3 --tries=3 + autostart=true + autorestart=true + user=forge + numprocs=8 + redirect_stderr=true + stdout_logfile=/home/forge/app.com/worker.log - php artisan queue:work connection --daemon +In this example, the `numprocs` directive will instruct Supervisor to run 8 `queue:work` processes and monitor all of them, automatically restarting them if they fail. Of course, you should change the `queue:work sqs` portion of the `command` directive to reflect your desired queue connection. - php artisan queue:work connection --daemon --sleep=3 +#### Starting Supervisor - php artisan queue:work connection --daemon --sleep=3 --tries=3 +Once the configuration file has been created, you may update the Supervisor configuration and start the processes using the following commands: -As you can see, the `queue:work` command supports most of the same options available to `queue:listen`. You may use the `php artisan help queue:work` command to view all of the available options. + sudo supervisorctl reread -### Deploying With Daemon Queue Workers + sudo supervisorctl update -The simplest way to deploy an application using daemon queue workers is to put the application in maintenance mode at the beginning of your deploymnet. This can be done using the `php artisan down` command. Once the application is in maintenance mode, Laravel will now accept any new jobs off of the queue, but will continue to process existing jobs. Once enough time has passed for all of your existing jobs to execute (usually no longer than 30-60 seconds), you may stop the worker and continue your deployment process. + sudo supervisorctl start laravel-worker:* -If you are using Supervisor or Laravel Forge, which utilizes Supervisor, you may typically stop a worker with a command like the following: +For more information on Supervisor, consult the [Supervisor documentation](http://supervisord.org/index.html). - supervisorctl stop worker-1 + +## Dealing With Failed Jobs -Once the queues have been drained and your fresh code has been deployed to your server, you should restart the daemon queue work. If you are using Supervisor, this can typically be done with a command like this: +Sometimes your queued jobs will fail. Don't worry, things don't always go as planned! Laravel includes a convenient way to specify the maximum number of times a job should be attempted. After a job has exceeded this amount of attempts, it will be inserted into the `failed_jobs` database table. To create a migration for the `failed_jobs` table, you may use the `queue:failed-table` command: - supervisorctl start worker-1 + php artisan queue:failed-table - -## Push Queues + php artisan migrate -Push queues allow you to utilize the powerful Laravel 4 queue facilities without running any daemons or background listeners. Currently, push queues are only supported by the [Iron.io](http://iron.io) driver. Before getting started, create an Iron.io account, and add your Iron credentials to the `app/config/queue.php` configuration file. +Then, when running your [queue worker](#running-the-queue-worker), you should specify the maximum number of times a job should be attempted using the `--tries` switch on the `queue:work` command. If you do not specify a value for the `--tries` option, jobs will be attempted indefinitely: -#### Registering A Push Queue Subscriber + php artisan queue:work redis --tries=3 -Next, you may use the `queue:subscribe` Artisan command to register a URL end-point that will receive newly pushed queue jobs: + +### Cleaning Up After Failed Jobs - php artisan queue:subscribe queue_name http://foo.com/queue/receive +You may define a `failed` method directly on your job class, allowing you to perform job specific clean-up when a failure occurs. This is the perfect location to send an alert to your users or revert any actions performed by the job. The `Exception` that caused the job to fail will be passed to the `failed` method: -Now, when you login to your Iron dashboard, you will see your new push queue, as well as the subscribed URL. You may subscribe as many URLs as you wish to a given queue. Next, create a route for your `queue/receive` end-point and return the response from the `Queue::marshal` method: + -## Failed Jobs + class ProcessPodcast implements ShouldQueue + { + use InteractsWithQueue, Queueable, SerializesModels; -Since things don't always go as planned, sometimes your queued jobs will fail. Don't worry, it happens to the best of us! Laravel includes a convenient way to specify the maximum number of times a job should be attempted. After a job has exceeded this amount of attempts, it will be inserted into a `failed_jobs` table. The failed jobs table name can be configured via the `app/config/queue.php` configuration file. + protected $podcast; -To create a migration for the `failed_jobs` table, you may use the `queue:failed-table` command: + /** + * Create a new job instance. + * + * @param Podcast $podcast + * @return void + */ + public function __construct(Podcast $podcast) + { + $this->podcast = $podcast; + } - php artisan queue:failed-table + /** + * Execute the job. + * + * @param AudioProcessor $processor + * @return void + */ + public function handle(AudioProcessor $processor) + { + // Process uploaded podcast... + } -You can specify the maximum number of times a job should be attempted using the `--tries` switch on the `queue:listen` command: + /** + * The job failed to process. + * + * @param Exception $exception + * @return void + */ + public function failed(Exception $exception) + { + // Send user notification of failure, etc... + } + } - php artisan queue:listen connection-name --tries=3 + +### Failed Job Events -If you would like to register an event that will be called when a queue job fails, you may use the `Queue::failing` method. This event is a great opportunity to notify your team via e-mail or [HipChat](https://www.hipchat.com). +If you would like to register an event that will be called when a job fails, you may use the `Queue::failing` method. This event is a great opportunity to notify your team via email or [HipChat](https://www.hipchat.com). For example, we may attach a callback to this event from the `AppServiceProvider` that is included with Laravel: - Queue::failing(function($connection, $job, $data) - { - // - }); + connectionName + // $event->job + // $event->exception + }); + } - php artisan queue:retry 5 + /** + * Register the service provider. + * + * @return void + */ + public function register() + { + // + } + } + + +### Retrying Failed Jobs + +To view all of your failed jobs that have been inserted into your `failed_jobs` database table, you may use the `queue:failed` Artisan command: + + php artisan queue:failed + +The `queue:failed` command will list the job ID, connection, queue, and failure time. The job ID may be used to retry the failed job. For instance, to retry a failed job that has an ID of `5`, issue the following command: + + php artisan queue:retry 5 + +To retry all of your failed jobs, execute the `queue:retry` command and pass `all` as the ID: + + php artisan queue:retry all If you would like to delete a failed job, you may use the `queue:forget` command: - php artisan queue:forget 5 + php artisan queue:forget 5 To delete all of your failed jobs, you may use the `queue:flush` command: - php artisan queue:flush + php artisan queue:flush + + +## Job Events + +Using the `before` and `after` methods on the `Queue` [facade](/docs/{{version}}/facades), you may specify callbacks to be executed before or after a queued job is processed. These callbacks are a great opportunity to perform additional logging or increment statistics for a dashboard. Typically, you should call these methods from a [service provider](/docs/{{version}}/providers). For example, we may use the `AppServiceProvider` that is included with Laravel: + + connectionName + // $event->job + // $event->job->payload() + }); + + Queue::after(function (JobProcessed $event) { + // $event->connectionName + // $event->job + // $event->job->payload() + }); + } + + /** + * Register the service provider. + * + * @return void + */ + public function register() + { + // + } + } + +Using the `looping` method on the `Queue` [facade](/docs/{{version}}/facades), you may specify callbacks that execute before the worker attempts to fetch a job from a queue. For example, you might register a Closure to rollback any transactions that were left open by a previously failed job: + + Queue::looping(function () { + while (DB::transactionLevel() > 0) { + DB::rollBack(); + } + }); diff --git a/quick.md b/quick.md deleted file mode 100755 index 4a38929..0000000 --- a/quick.md +++ /dev/null @@ -1,178 +0,0 @@ -# Laravel Quickstart - -- [Installation](#installation) -- [Routing](#routing) -- [Creating A View](#creating-a-view) -- [Creating A Migration](#creating-a-migration) -- [Eloquent ORM](#eloquent-orm) -- [Displaying Data](#displaying-data) - - -## Installation - -### Laravel Installer ကို အသုံးပြုခြင်း - -ရှေးဦးစွာ [Laravel installer PHAR archive](http://laravel.com/laravel.phar) ကို ဒေါင်းပါ။ အဆင်ပြေစေရန်အတွက် ထို file ကို `laravel` ဟု အမည်ပေးပြီး `/usr/local/bin` ထဲသို ့ပြောင်းရွေ ့လိုက်ပါ။ ထိုနောက် `laravel new` command ဖြင့် သင်ထားရှိထားသော directory ပေါ်တွင် laravel installation အလိုအလျောက် ပြလုပ်သွားမည် ဖြစ်သည်။ ဥပမာ `laravel new blog` ဆိုသည့် command ကိုအသုံးပြပါက `blog` အမည်ရှိ folder တစ်ခုကို တည်ဆောက်ပေးပြီး လိုအပ်သည့် package များကိုပါ တခါတည်း ဒေါင်းလုပ်လုပ်ကာ စုစည်းပေးသွားမည် ဖြစ်သည်။ ၄င်းသို ့ install ပြုလုပ်ခြင်းသည် Composer မှ install လုပ်ခြင်းထက် ပို၍ လျင်မြန်ပါလိမ့်မည်။ - -### Composer ကို အသုံးပြုခြင်း - -Laravel framework ကို [Composer](http://getcomposer.org) မှလည်း installation နှင့် လိုအပ်သည့် package များကို ထည့်သွင်းနိုင်သည်။ Composer မသွင်းရသေးပါက [Composer ထည့်သွင်းခြင်းနည်းလမ်း](http://getcomposer.org/doc/00-intro.md) ကိုကြည့်၍ ထည့်သွင်းနိုင်ပါသည်။ - -ထိုနောက် သင့်အနေဖြင့် terminal မှ အောက်ပါ command ကို ရိုက်သွင်းခြင်းဖြင့် Laravel ကို install ပြုလုပ်နိုင်မည် ဖြစ်သည်။ - - composer create-project laravel/laravel your-project-name --prefer-dist - -၄င်း command မှ laravel အသစ်စက်စက် ကို သင့်`your-project-name` folder အတွင်းတွင် တည်ရှိနေမည်ကို တွေ ့ရပါမည်။ - -ထိုတင်မက သင့် အနေဖြင့် [Laravel repository from Github](https://github.com/laravel/laravel/archive/master.zip) မှ ဒေါင်းလော့ ပြုလုပ်ပြီး directory ထဲတွင် `composer install` run ၍လည်း install ပြုလုပ်နိုင်ပါသည်။ ထို command မှ framework တွင် လိုအပ်သော package များကို အလိုအလျောက် download ပြုလုပ်ပြီး install သွားမည် ဖြစ်သည်။ - -### Permissions - -Laravel ကို install ပြုလုပ်ပြီးပါက သင့်အနေဖြင့် web server ၏ write permission ဖြင့်ပတ်သတ်၍ `app/storage` ထဲတွင် ပြင်ဆင်ရန် လိုအပ်ကောင်း လိုအပ်ပေမည်။ အသေးစိတ် အချက်အလက်ကို [Installation](installation.md) တွင် ကြည့်ရှုနိုင်ပါသည်။ - -### Serving Laravel - -အကြမ်းအားဖြင့် Apache သို ့မဟုတ် Nginx ပေါ်တွင် laravel application ကို တင်ထားနိုင်သည်။ သင့် အသုံးပြုသော PHP version မှာ 5.4 အထက်ဖြစ်ပြီး PHP တွင်ပါဝင်သော default server ကို အသုံးပြုလိုပါက သင့်အနေဖြင့် Artisan command ဖြစ်သည့် `serve` ကို အသုံးပြုနိုင်သည်။ - - php artisan serve - - -### Directory Structure - -Framework ကို install ပြုလုပ်ပြီးနောက် သင့် အနေဖြင့် directory structure ဖြင့် ရင်းနှီးနေရန် လိုပေမည်။ `app` directory ထဲတွင် `views`, `controllers`, and `models` အစရှိသည့် folder များ တည်ရှိနေသည်ကို တွေ ့ ရမည် ဖြစ်သည်။ သင့် application ၏ code များကို ထိုထဲတွင် ရေးသားရမည် ဖြစ်သည်။ သင့်အနေဖြင့် လိုအပ်မည့် configuration နှင့် ပတ်သတ်၍ `app/config` အမည်ရှိ directory ထဲတွင်ကြည့်ရှုရမည် ဖြစ်သည်။ - - -## Routing - -ရှေးဦးစွာ Route တစ်ခုကို တည်ဆောက်ကြပါစို ့။ Laravel တွင် အရိုးရှင်းဆုံး route မှာ route to Closure ဖြစ်သည်။ `app/routes.php` ကိုဖွင့်ပြီး အောက်ပါ code ကိုထည့်သွင်းကြည့်ပါ။ - - Route::get('users', function() - { - return 'Users!'; - }); - -ထိုနောက် web browser ပေါ်တွင် `/users` ဟူသော route ဖြင့် စမ်းကြည့်ပါက သင့်အနေဖြင့် `Users!` တုံ ့ပြန်သည်ကို မြင်တွေ ့ရမည် ဖြစ်သည်။ -ကောင်းလေစွ! သင့်အနေဖြင့် ပထမဦးစွာ route တစ်ခုကို ဖန်တီးလိုက်ပြီ ဖြစ်သည်။ - - -Route များမှာ controller များနှင့်လည်း ချိတ်ဆက် အလုပ်လုပ်နိုင်သည်။ ဥပမာ - - Route::get('users', 'UserController@getIndex'); - -အဆိုပါ route တွင် `/users` ဟုခေါ်ယူလိုက်ပါက `UserController` class အတွင်းရှိ `getIndex` method ကို အလုပ်လုပ်မည် ဖြစ်သည်။ Controller routing နှင့် ပတ်သတ်၍ အသေးစိတ်ကို [controller documentation](controllers.md) တွင်ကြည့်ရှုနိုင်သည်။ - - -## View တစ်ခု တည်ဆောက်ခြင်း - -ထိုနောက် user data များကို ဖော်ပြရန် ရိုးရှင်းသည့် view တစ်ခုကို တည်ဆောက်ရန် လိုပေမည်။ view file များသည် `app/views` directory ထဲတွင် တည်ရှိမည် ဖြစ်သည်။ View တွင် သင့် application တွင် ဖော်ပြလိုသည့် HTML ဖြင့် ဖော်ပြသွားမည် ဖြစ်သည်။ `layout.blade.php` နှင့် `users.blade.php` ဟု၍ file နှစ်ခုကို တည်ဆောက်လိုက်ပါ။ `layout.blade.php` ဟုသည့် file တွင် အောက်ပါ အတိုင်း ရေးသားလိုက်ပါ။ - - - -

    Laravel Quickstart

    - - @yield('content') - - - -ထိုနောက် `users.blade.php` ဟုသော view တစ်ခုကို တည်ဆောက် လတ္တံ ့။ - - @extends('layout') - - @section('content') - Users! - @stop - -တချို ့သော syntax များမှ သင့်အတွက် နည်းနည်း စိမ်းနေမည် ဖြစ်သည်။ အဘယ်ကြောင့်ဆိုသော် ယခု အသုံးပြုထားသည်မှာ Laravel ၏ templating system ဖြစ်သည့် Blade ကို အသုံးပြုထားခြင်း ကြောင့် ဖြစ်သည်။ Blade သည် အလွန်မြန်ဆန် လှပေသည်။ အကြောင်းမှာ ရိုးရှင်းလွယ်ကူ regular expression များကို အသုံးပြုကာ PHP အဖြစ်သို ့ compile ပြုလုပ်ထားခြင်းကြောင့်ဖြစ်သည်။ Blade အနေဖြင့် အလွန်တရာ စွမ်းအင်ကြီးမားလှသော template inheritance ကဲ့သို ့သော feature များကို support ပေးရုံသာမက PHP တွင် ရေးသားနိုင်သည့် `if` နှင့် `for` သို ့သော Conditional statement များကိုပါ သေသပ်လှပစွာ ရေးသားနိုင်သောကြောင့်ဖြစ်သည်။ အသေးစိတ်ကို [Blade documentation](templates.md) ကြည့်ရှုနိုင်ပေမည်။ - -ယခု ကျွန်တော်တို ့ views အပိုင်းကို ဖန်တီးပြီး ဖြစ်၍ `/users` ဟုသော route ဘက်ကို ပြန်လှည့်ကြပါစို ့။ Route မှ `Users!` ဟု return ပြန်ခြင်းထက် -view ကို ပြန်ပေးဖို ့လိုပေမည်။ - - Route::get('users', function() - { - return View::make('users'); - }); - -အံသြဖွယ်ကောင်းလေစွ။ သင့်အနေဖြင့် layout တစ်ခုကို extends ပြုလုပ်ထားသော view တစ်ခုကို တည်ဆောက်ပြီးပေသည်။ ဆက်၍ database layer တွင် ဆက်၍ လှုပ်ရှားကြပါစို ့။ - - -## Migration တစ်ခုဖန်တီးခြင်း - -Table တစ်ခုတည်ဆောက်ပြီး data တွေကို handle နိုင်ရန် Laravel migration system ကို အသုံးပြုရန်လိုပေမည်။ Migration အနေဖြင့် သင့် database ၏ modification ကို အလွယ်တကူ သတ်မှတ်နိုင်ပြီး သင့်အဖွဲ ့သားများနှင့် မျှဝေနိုင်ပေမည်။ - -ရှေးဦးစွာ database နှင့် ချိတ်ဆက်ရန် လိုပေမည်။ database ဖြင့်ချိတ်ဆက်ရန် အတွက် `app/config/database.php` တွင် ပြင်ဆင်ရန်လိုပေမည်။ ပုံမှန်အားဖြင့် Laravel သည် MySQL ဖြင့် အသုံးပြုရန် သတ်မှတ်ထားသည်။ သင့်အနေဖြင့် လိုအပ်သော credential များကို config file တွင် ဖြည့်သွင်းရန်လိုပေမည်။ သင့်အနေဖြင့် အလိုရှိပါက စိတ်ကြိုက် `driver` option ကို `sqlite` ဖြစ်စေပြောင်းလဲနိုင်ပြီ။ ၄င်းအနေဖြင့် `app/database` directory အောက်တွင် တည်ရှိမည့် SQLite database ကို အလုပ်လုပ်မည် ဖြစ်သည်။ - -ထိုနောက် migration တစ်ခု ဖန်တီးရန် [Artisan CLI](artisan.md) ကို အသုံးပြုမည် ဖြစ်သည်။ project ၏ root တွင် အောက်ပါ အတိုင်း terminal မှ run ရန် လိုပေမည်။ - - php artisan migrate:make create_users_table - -ဆက်၍ `app/database/migrations` တည်ရှိသည့် migration file ကို ရှာရန် လိုပေမည်။ ထိုထဲတွင် `up` နှင့်`down`ဟူသော method နှစ်ခုပါဝင်မည် ဖြစ်သည်။ - - -`up` method တွင် database တွင် ပြောင်းလဲချင်သည်များကို ထည့်သွင်းရေးသား၍ `down` method ပြောင်းပြန်ရေးသားရမည် ဖြစ်သည်။ -အောက်ပါအတိုင်း migration ကို တည်ဆောက်လိုက်ပါ။ - - public function up() - { - Schema::create('users', function($table) - { - $table->increments('id'); - $table->string('email')->unique(); - $table->string('name'); - $table->timestamps(); - }); - } - - public function down() - { - Schema::drop('users'); - } - -ဆက်၍ migrate ပြုလုပ်လိုပါက terminal တွင်`migrate` ဟုရိုက်ရန်လိုပေမည်။ - - php artisan migrate - -migration တစ်ခုကို rollback (နောက်ပြန်လှည့်) လိုပါက သင့်အနေဖြင့် `migrate:rollback` ဟူ၍ ရိုက်ရုံသာ ဖြစ်သည်။ ယခု database table ရှိပြီ ဖြစ်၍ -data လေးနည်းနည်းဖြင့် စလိုက်ကြပါစို ့။ - - -## Eloquent ORM - -Eloquent ORM သည် Laravel ၏ အလှတရား တစ်ရပ်ပင်ဖြစ်သည်။ သင့်အနေဖြင့် Ruby on Rails framework ကို အသုံးပြုဖူးပါက ၄င်းကဲ့သို ့ database interaction ပြုလုပ်ရာတွင် ActiveRecord ORM style သုံးထားသာ Eloquent နှင့်ရင်းနှီးနေမည် ဖြစ်သည်။ - -ပထမဦးဆုံး model တစ်ခုကို သတ်မှတ်ကြပါစို ့။ Eloquent model တစ်ခုသည် ဆက်စပ်နေသော database table များ၏ query ကိုပါ အသုံးပြုနိုင်သည်။ သိပ်များ နားရှုပ်သွားသလား မသိ။ အခုလာမယ့် အပိုင်းမှာ တဖြည်းဖြည်း နားလည်လာမှာပါ။ Model တွေဟာ `app/models` ဆိုတဲ့ directory အတွင်းမှာ တည်ရှိပါတယ်။ အဆိုပါ directory ထဲမှာ အောက်ပါအတိုင်း `User.php` ဆိုတဲ့ model တစ်ခုကို တည်ဆောက်လိုက်ပါ။ - - class User extends Eloquent {} - -သတိပြုရမည်မှာ ကျွန်တော်တို ့အနေဖြင့် Eloquent ကို မည်သည့် table အသုံးပြုရန် မညွန်းဆိုရသေးချေ။ Eloquent တွင် အသုံးပြုနည်း များစွာ ရှိသည့် အနက်တစ်ခုမှာ Model အမည်၏ အများကိန်းမှာ database table အဖြစ် အလိုအလျောက် သိရှိနေမည် ဖြစ်သည်။ အဆင်ပြေလေစွ! - -သင့်အနေဖြင့် ကြိုက်သည့် database administration tool ကို အသုံးပြုပြီး `users` table တွင် row အနည်းငယ် data သွင်းလိုက်ပါ။ ထိုနောက် Eloquent ကို အသုံးပြု၍ data များကို ထုတ်ယူပြီး view သို ့လွဲပြောင်းပေးလိုက်မည်။ - -ယခု `/users` route ကို အောက်ပါပုံစံပြောင်းလဲလိုက်ပါ။ - - Route::get('users', function() - { - $users = User::all(); - - return View::make('users')->with('users', $users); - }); - -အထက်ပါ route ကိုကြည့်ပါ။ ရှေးဦးစွာ `User` model မှ `all` method မှာ `users` table မှ rows အားလုံးကို ထုတ်ပေးမည် ဖြစ်သည်။ ထိုနောက် ထို record များကို `with` method အသုံးပြု၍ view သို ့ passing ပေးလိုက်ခြင်း ဖြစ်သည်။ ထို `with` method သည် key နှင့် value အနေဖြင့် data များကို လက်ခံမည် ဖြစ်သည်။ ထိုအခါ view သို ့ data များရောက်သွားမည် ဖြစ်သည်။ - -ကောင်းလေးစွ။ ယခု ကျွန်တော်တို ့ user ကို data များ ပြသနိုင်ရန် အဆင်သင့်ဖြစ်ချေပြီ။ - - -## Data များ ပြသခြင်း - -ယခုအခါ `users` ကို view တွင် မြင်သာစေရန် ပြုလုပ်ပြီးပြီဖြစ်သည်။ ကျွန်တော်တို ့ အောက်ပါ အတိုင်း ပြသနိုင်လေပြီ။ - - @extends('layout') - - @section('content') - @foreach($users as $user) -

    {{ $user->name }}

    - @endforeach - @stop - -သင့်အနေဖြင့် `echo` statements ကိုရှာနေလား မသိ။ Blade ကို အသုံးပြုရာတွင် data များကို တွန် ့ကွင်း နှစ်ခု အကြား ထည့်သွင်းခြင်းဖြင့် data များကို echo အစား ပြသပေးနိုင်သည်။ ဘယ်လောက်များ လွယ်ကူပေသလဲ။ ယခုအခါ သင့်အနေဖြင့် `/users` route ကို လှမ်းခေါ်လိုက်ခြင်းဖြင့် သင့် users များကို ပြသနိုင်လေပြီ။ - -အထက်ပါ ဥပမာဟာ အစသာရှိပါသေးသည်။ ထို tutorial တွင် သင့်အနေဖြင့် laravel ၏ အခြေခံကို တွေ ့မြင်နိုင်မည် ဖြစ်သည်။ သို ့သော်လည်း ပိုမို၍ စိတ်လှုပ်ရှားစရာ အချက်များစွာ စီတန်း၍ လေ့လာရန် ကျန်ရှိနေပါသေးသည်။ documentation ကို ဖတ်ရှုခြင်းဖြင့် စွမ်းအားကြီးမားလှသည့် [Eloquent](eloquent) နှင့် [Blade](/docs/templates) ကဲ့သို ့သော သို ့မဟုတ် သင့်ပိုစိတ်ဝင်စားနိုင်သည့် [Queues](/docs/queues) နှင့် [Unit Testing](/docs/testing) ကဲ့သို ့သော အကြောင်းအရာများကို လေ့လာနိုင်သည်။ ထပ်၍ သင့် application ၏ architecture ကို သက်တောင့်သက်သာ ဖြစ်စေမည့် [IoC Container](/docs/ioc.md) များလည်း ပါဝင်ပါသေးသည်။ ရွေးချယ်ပါလော့။ diff --git a/readme.md b/readme.md old mode 100755 new mode 100644 index 1da2956..9b55bba --- a/readme.md +++ b/readme.md @@ -1,15 +1,5 @@ -ရည်ရွယ်ချက် ---------- +# Laravel Documentation -ကျွန်တော်တို့ အခုမှစပြီး ဘာသာပြန်နေတုံးပါ၊ ရည်ရွယ်ချက် ကတော့ Laravel PHP Framework Documencation ကို မြန်မာလို ဖတ်ပြီး Laravel Framework ကို အလွယ်တကူ လေ့လာနိုင်ဖို့ပါ၊ - -ဒီဘာသာပြန်မှုမှာ ဘယ်လို ဘာဝင်ကူညီနိုင်လဲ --------------------- - -ဟုတ်ကဲ့ ကျွန်တော်တို့လည်းအလုပ်နဲ့ပါ အားတဲ့အချိန်လေးဘာသာပြန်ပြီးတော့ဒီမှာတင်တာပါ။ တကယ်လို့ကျွန်တော်တို့ကို ကူညီပြီးဘာသာပြန်ချင်တယ်ဆိုရင်ဒီ Repo မှာ pull request လုပ်ပြီး contribute လုပ်နိုင်ပါတယ်။ ကျွန်တော်တို့ဘာသာပြန်ပြီးသားတွေကိုလည်း စာလုံးပေါင်းအမှားတွေကို git issue တွေပေးနိုင်ပါတယ်။ [Contribute Guide](contributing.md) ကိုဖတ်ပေးပါ။ - -ဆက်သွယ်ရန် -------- - -- [Laravel Myanmar Facebook Group](https://www.facebook.com/groups/250409601822202/) +## Contribution Guidelines +If you are submitting documentation for the **current stable release**, submit it to the corresponding branch. For example, documentation for Laravel 5.1 would be submitted to the `5.1` branch. Documentation intended for the next release of Laravel should be submitted to the `master` branch. diff --git a/redirects.md b/redirects.md new file mode 100644 index 0000000..e31c97b --- /dev/null +++ b/redirects.md @@ -0,0 +1,88 @@ +# HTTP Redirects + +- [Creating Redirects](#creating-redirects) +- [Redirecting To Named Routes](#redirecting-named-routes) +- [Redirecting To Controller Actions](#redirecting-controller-actions) +- [Redirecting With Flashed Session Data](#redirecting-with-flashed-session-data) + + +## Creating Redirects + +Redirect responses are instances of the `Illuminate\Http\RedirectResponse` class, and contain the proper headers needed to redirect the user to another URL. There are several ways to generate a `RedirectResponse` instance. The simplest method is to use the global `redirect` helper: + + Route::get('dashboard', function () { + return redirect('home/dashboard'); + }); + +Sometimes you may wish to redirect the user to their previous location, such as when a submitted form is invalid. You may do so by using the global `back` helper function. Since this feature utilizes the [session](/docs/{{version}}/session), make sure the route calling the `back` function is using the `web` middleware group or has all of the session middleware applied: + + Route::post('user/profile', function () { + // Validate the request... + + return back()->withInput(); + }); + + +## Redirecting To Named Routes + +When you call the `redirect` helper with no parameters, an instance of `Illuminate\Routing\Redirector` is returned, allowing you to call any method on the `Redirector` instance. For example, to generate a `RedirectResponse` to a named route, you may use the `route` method: + + return redirect()->route('login'); + +If your route has parameters, you may pass them as the second argument to the `route` method: + + // For a route with the following URI: profile/{id} + + return redirect()->route('profile', ['id' => 1]); + +#### Populating Parameters Via Eloquent Models + +If you are redirecting to a route with an "ID" parameter that is being populated from an Eloquent model, you may simply pass the model itself. The ID will be extracted automatically: + + // For a route with the following URI: profile/{id} + + return redirect()->route('profile', [$user]); + +If you would like to customize the value that is placed in the route parameter, you should override the `getRouteKey` method on your Eloquent model: + + /** + * Get the value of the model's route key. + * + * @return mixed + */ + public function getRouteKey() + { + return $this->slug; + } + + +## Redirecting To Controller Actions + +You may also generate redirects to [controller actions](/docs/{{version}}/controllers). To do so, pass the controller and action name to the `action` method. Remember, you do not need to specify the full namespace to the controller since Laravel's `RouteServiceProvider` will automatically set the base controller namespace: + + return redirect()->action('HomeController@index'); + +If your controller route requires parameters, you may pass them as the second argument to the `action` method: + + return redirect()->action( + 'UserController@profile', ['id' => 1] + ); + + +## Redirecting With Flashed Session Data + +Redirecting to a new URL and [flashing data to the session](/docs/{{version}}/session#flash-data) are usually done at the same time. Typically, this is done after successfully performing an action when you flash a success message to the session. For convenience, you may create a `RedirectResponse` instance and flash data to the session in a single, fluent method chain: + + Route::post('user/profile', function () { + // Update the user's profile... + + return redirect('dashboard')->with('status', 'Profile updated!'); + }); + +After the user is redirected, you may display the flashed message from the [session](/docs/{{version}}/session). For example, using [Blade syntax](/docs/{{version}}/blade): + + @if (session('status')) +
    + {{ session('status') }} +
    + @endif diff --git a/redis.md b/redis.md old mode 100755 new mode 100644 index a1270d1..b14b2e1 --- a/redis.md +++ b/redis.md @@ -1,88 +1,236 @@ # Redis -- [အစပျိုး](#introduction) -- [Configuration](#configuration) -- [Usage](#usage) -- [Pipelining](#pipelining) +- [Introduction](#introduction) + - [Configuration](#configuration) + - [Predis](#predis) + - [PhpRedis](#phpredis) +- [Interacting With Redis](#interacting-with-redis) + - [Pipelining Commands](#pipelining-commands) +- [Pub / Sub](#pubsub) -## အစပျိုး +## Introduction -[Redis](http://redis.io) သည် open source advanced key-value store တစ်ခုဖြစ်သည်။ ၄င်းသည် keys များတွင် [strings](http://redis.io/topics/data-types#strings), [hashes](http://redis.io/topics/data-types#hashes), [lists](http://redis.io/topics/data-types#lists), [sets](http://redis.io/topics/data-types#sets), and [sorted sets](http://redis.io/topics/data-types#sorted-sets) ပါဝင်သောကြောင့် ရံဖန်ရံခါ data structure server ဟု သတ်မှတ်ခြင်း ခံရသည်။ +[Redis](http://redis.io) is an open source, advanced key-value store. It is often referred to as a data structure server since keys can contain [strings](http://redis.io/topics/data-types#strings), [hashes](http://redis.io/topics/data-types#hashes), [lists](http://redis.io/topics/data-types#lists), [sets](http://redis.io/topics/data-types#sets), and [sorted sets](http://redis.io/topics/data-types#sorted-sets). -> **Note:** သင့်တွင် Redis PHP extension ကို PECL မှ တဆင့် သွင်းပြီးပါက Redis အတွက် အတိုကောက် အမည်ကို `app/config/app.php` ကြေညာပေးရမည်။ +Before using Redis with Laravel, you will need to install the `predis/predis` package via Composer: + + composer require predis/predis + +Alternatively, you may install the [PhpRedis](https://github.com/phpredis/phpredis) PHP extension via PECL. The extension is more complex to install but may yield better performance for applications that make heavy use of Redis. -## Configuration +### Configuration + +The Redis configuration for your application is located in the `config/database.php` configuration file. Within this file, you will see a `redis` array containing the Redis servers utilized by your application: + + 'redis' => [ + + 'client' => 'predis', + + 'default' => [ + 'host' => env('REDIS_HOST', 'localhost'), + 'password' => env('REDIS_PASSWORD', null), + 'port' => env('REDIS_PORT', 6379), + 'database' => 0, + ], + + ], + +The default server configuration should suffice for development. However, you are free to modify this array based on your environment. Each Redis server defined in your configuration file is required to have a name, host, and port. + +#### Configuring Clusters + +If your application is utilizing a cluster of Redis servers, you should define these clusters within a `clusters` key of your Redis configuration: + + 'redis' => [ + + 'client' => 'predis', + + 'clusters' => [ + 'default' => [ + [ + 'host' => env('REDIS_HOST', 'localhost'), + 'password' => env('REDIS_PASSWORD', null), + 'port' => env('REDIS_PORT', 6379), + 'database' => 0, + ], + ], + ], + + ], + +By default, clusters will perform client-side sharding across your nodes, allowing you to pool nodes and create a large amount of available RAM. However, note that client-side sharding does not handle failover; therefore, is primarily suited for cached data that is available from another primary data store. If you would like to use native Redis clustering, you should specify this in the `options` key of your Redis configuration: + + 'redis' => [ + + 'client' => 'predis', + + 'options' => [ + 'cluster' => 'redis', + ], + + 'clusters' => [ + // ... + ], + + ], + + +### Predis + +In addition to the default `host`, `port`, `database`, and `password` server configuration options, Predis supports additional [connection parameters](https://github.com/nrk/predis/wiki/Connection-Parameters) that may be defined for each of your Redis servers. To utilize these additional configuration options, simply add them to your Redis server configuration in the `config/database.php` configuration file: + + 'default' => [ + 'host' => env('REDIS_HOST', 'localhost'), + 'password' => env('REDIS_PASSWORD', null), + 'port' => env('REDIS_PORT', 6379), + 'database' => 0, + 'read_write_timeout' => 60, + ], + + +### PhpRedis + +> {note} If you have the PhpRedis PHP extension installed via PECL, you will need to rename the `Redis` alias in your `config/app.php` configuration file. + +To utilize the PhpRedis extension, you should change the `client` option of your Redis configuration to `phpredis`. This option is found in your `config/database.php` configuration file: + + 'redis' => [ + + 'client' => 'phpredis', + + // Rest of Redis configuration... + ], + +In addition to the default `host`, `port`, `database`, and `password` server configuration options, PhpRedis supports the following additional connection parameters: `persistent`, `prefix`, `read_timeout` and `timeout`. You may add any of these options to your Redis server configuration in the `config/database.php` configuration file: + + 'default' => [ + 'host' => env('REDIS_HOST', 'localhost'), + 'password' => env('REDIS_PASSWORD', null), + 'port' => env('REDIS_PORT', 6379), + 'database' => 0, + 'read_timeout' => 60, + ], + + +## Interacting With Redis + +You may interact with Redis by calling various methods on the `Redis` [facade](/docs/{{version}}/facades). The `Redis` facade supports dynamic methods, meaning you may call any [Redis command](http://redis.io/commands) on the facade and the command will be passed directly to Redis. In this example, we will call the Redis `GET` command by calling the `get` method on the `Redis` facade: + + array( + return view('user.profile', ['user' => $user]); + } + } - 'cluster' => true, +Of course, as mentioned above, you may call any of the Redis commands on the `Redis` facade. Laravel uses magic methods to pass the commands to the Redis server, so simply pass the arguments the Redis command expects: - 'default' => array('host' => '127.0.0.1', 'port' => 6379), + Redis::set('name', 'Taylor'); - ), + $values = Redis::lrange('names', 5, 10); -default server configuration မှာ development အတွက် ဦးတည်ထားသော်လည်း မိမိတို ့စိတ်ကြိုက် ထို array ကိုပြောင်းလဲ သတ်မှတ်နိုင်သည်။ -ထို Redis server ၏ name ၊ host နှင့် Server မှ အသုံးပြုသည့် port ကို ကြေညာပေးရန်လိုပေမည်။ +Alternatively, you may also pass commands to the server using the `command` method, which accepts the name of the command as its first argument, and an array of values as its second argument: + $values = Redis::command('lrange', ['name', 5, 10]); - Laravel Redis client ကို `cluster` option မှ Redis nodes များ အကြား client-side sharding ပြုလုပ်ရန် ညွန်ကြားခြင်းဖြင့် Nodes များမှ data ဆွဲယူပြီး RAM အတွက် နေရာလွတ်များ ဖန်တီးနိုင်မည် ဖြစ်သည်။ သို ့သော် client-side sharding သည် failover ကို ကိုင်တွယ်နိုင်ခြင်း မရှိပေ။ ထိုကြောင့် - Primary data store များ ရရှိနိုသည့် အခြေအနေတွင် cache data များ ထုတ်လွတ်ပေးသူ အဖြစ် အသုံးဝင်သည်။ +#### Using Multiple Redis Connections -Redis Server အနေဖြင့် စိစစ်ရန်လိုအပ်ပါက Redis Server Configuration array အတွင်း `password` key / value pair ကို ထည့်သွင်းနိုင်သည်။ +You may get a Redis instance by calling the `Redis::connection` method: - -## အသုံးပြုပုံ + $redis = Redis::connection(); +This will give you an instance of the default Redis server. You may also pass the connection or cluster name to the `connection` method to get a specific server or cluster as defined in your Redis configuration: - `Redis::connection` method ကို ခေါ်ယူခြင်းဖြင့် Redis instance ကိုရယူနိုင်သည်။ + $redis = Redis::connection('my-connection'); - $redis = Redis::connection(); + +### Pipelining Commands -၄င်းသည် default Redis server ၏ instance ကို ပြန်ပေးမည် ဖြစ်သည်။ Server clustering ကို အသုံးပြုနေသည် မဟုတ်ပါက `connection` method -တွင် မိမိတို ့ အသုံးပြုနေသည့် server ၏ အမည်ကို configuration တွင် ထည့်သွင်းပေးရန် လိုအပ်ပေမည်။ +Pipelining should be used when you need to send many commands to the server in one operation. The `pipeline` method accepts one argument: a `Closure` that receives a Redis instance. You may issue all of your commands to this Redis instance and they will all be executed within a single operation: - $redis = Redis::connection('other'); + Redis::pipeline(function ($pipe) { + for ($i = 0; $i < 1000; $i++) { + $pipe->set("key:$i", $i); + } + }); -Redis ၏ instance ကို ရရှိသည်နှင့် တပြိုင်နက် [Redis commands](http://redis.io/commands) ကို အသုံးပြုနိုင်ပြီ ဖြစ်သည်။ Laravel အနေဖြင့် magic methods ကို အသုံးပြုပြီး Redis server သို ့ command များကို ပို ့ဆောင်ပေးသည်။ + +## Pub / Sub - $redis->set('name', 'Taylor'); +Laravel provides a convenient interface to the Redis `publish` and `subscribe` commands. These Redis commands allow you to listen for messages on a given "channel". You may publish messages to the channel from another application, or even using another programming language, allowing easy communication between applications and processes. - $name = $redis->get('name'); +First, let's setup a channel listener using the `subscribe` method. We'll place this method call within an [Artisan command](/docs/{{version}}/artisan) since calling the `subscribe` method begins a long-running process: - $values = $redis->lrange('names', 5, 10); + command('lrange', array(5, 10)); + class RedisSubscribe extends Command + { + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'redis:subscribe'; -default connection မှ ဆန် ့ကျင်ပြီး command များ အသုံးပြုလိုပါက `Redis` class မှ static magic method များကို အသုံးပြုနိုင်သည်။ + /** + * The console command description. + * + * @var string + */ + protected $description = 'Subscribe to a Redis channel'; - Redis::set('name', 'Taylor'); + /** + * Execute the console command. + * + * @return mixed + */ + public function handle() + { + Redis::subscribe(['test-channel'], function ($message) { + echo $message; + }); + } + } - $name = Redis::get('name'); +Now we may publish messages to the channel using the `publish` method: - $values = Redis::lrange('names', 5, 10); + Route::get('publish', function () { + // Route logic... -> **Note:** Laravel တွင် Redis [cache](cache) နှင့် [session](/docs/session.md) drivers များ ပါဝင်ပြီး ဖြစ်သည်။ + Redis::publish('test-channel', json_encode(['foo' => 'bar'])); + }); - -## Pipelining +#### Wildcard Subscriptions -Operation တစ်ခုအတွက် Command များစွာ ကို ပို ့လွတ်ရန် လိုအပ်ပါက Pipelining ကို အသုံးပြုရသည်။ ထို သို ့ ပြုလုပ်ရန် `pipeline` ကို အသုံးပြုရမည်။ +Using the `psubscribe` method, you may subscribe to a wildcard channel, which may be useful for catching all messages on all channels. The `$channel` name will be passed as the second argument to the provided callback `Closure`: -#### Server သို ့ Command များကို Piping ပြုလုပ်ခြင်း + Redis::psubscribe(['*'], function ($message, $channel) { + echo $message; + }); - Redis::pipeline(function($pipe) - { - for ($i = 0; $i < 1000; $i++) - { - $pipe->set("key:$i", $i); - } - }); \ No newline at end of file + Redis::psubscribe(['users.*'], function ($message, $channel) { + echo $message; + }); diff --git a/releases.md b/releases.md old mode 100755 new mode 100644 index f2f474c..fbecae7 --- a/releases.md +++ b/releases.md @@ -1,18 +1,1051 @@ # Release Notes +- [Support Policy](#support-policy) +- [Laravel 5.4](#laravel-5.4) +- [Laravel 5.3](#laravel-5.3) +- [Laravel 5.2](#laravel-5.2) +- [Laravel 5.1.11](#laravel-5.1.11) +- [Laravel 5.1.4](#laravel-5.1.4) +- [Laravel 5.1](#laravel-5.1) +- [Laravel 5.0](#laravel-5.0) - [Laravel 4.2](#laravel-4.2) - [Laravel 4.1](#laravel-4.1) + +## Support Policy + +For LTS releases, such as Laravel 5.1, bug fixes are provided for 2 years and security fixes are provided for 3 years. These releases provide the longest window of support and maintenance. For general releases, bug fixes are provided for 6 months and security fixes are provided for 1 year. + + +## Laravel 5.4 + +Laravel 5.4 continues the improvements made in Laravel 5.3 by adding support for [Markdown based emails and notifications](/docs/5.4/mail#markdown-mailables), the [Laravel Dusk](/docs/5.4/dusk) browser automation and testing framework, Laravel Mix, Blade "components" and "slots", route model binding on broadcast channels, higher order messages for Collections, object-based Eloquent events, job-level "retry" and "timeout" settings, "realtime" facades, improved support for Redis Cluster, custom pivot table models, middleware for request input trimming and cleaning, and more. In addition, the entire codebase of the framework was reviewed and refactored for general cleanliness. + +> {tip} This documentation summarizes the most notable improvements to the framework; however, more thorough change logs are always available [on GitHub](https://github.com/laravel/framework/blob/5.4/CHANGELOG-5.4.md). + +### Markdown Mail & Notifications + +> {video} There is a free [video tutorial](https://laracasts.com/series/whats-new-in-laravel-5-4/episodes/7) for this feature available on Laracasts. + +Markdown mailable messages allow you to take advantage of the pre-built templates and components of mail notifications in your mailables. Since the messages are written in Markdown, Laravel is able to render beautiful, responsive HTML templates for the messages while also automatically generating a plain-text counterpart. For example, a Markdown email might look something like the following: + + @component('mail::message') + # Order Shipped + + Your order has been shipped! + + @component('mail::button', ['url' => $url]) + View Order + @endcomponent + + Next Steps: + + - Track Your Order On Our Website + - Pre-Sign For Delivery + + Thanks,
    + {{ config('app.name') }} + @endcomponent + +Using this simple Markdown template, Laravel is able to generate a responsive HTML email and plain-text counterpart: + + + +To read more about Markdown mail and notifications, check out the full [mail](/docs/5.4/mail) and [notification](/docs/5.4/notifications) documentation. + +> {tip} You may export all of the Markdown mail components to your own application for customization. To export the components, use the `vendor:publish` Artisan command to publish the `laravel-mail` asset tag. + +### Laravel Dusk + +> {video} There is a free [video tutorial](https://laracasts.com/series/whats-new-in-laravel-5-4/episodes/9) for this feature available on Laracasts. + +Laravel Dusk provides an expressive, easy-to-use browser automation and testing API. By default, Dusk does not require you to install JDK or Selenium on your machine. Instead, Dusk uses a standalone [ChromeDriver](https://sites.google.com/a/chromium.org/chromedriver/home) installation. However, you are free to utilize any other Selenium compatible driver you wish. + +Since Dusk operates using a real browser, you are able to easily test and interact with your applications that heavily use JavaScript: + + /** + * A basic browser test example. + * + * @return void + */ + public function testBasicExample() + { + $user = factory(User::class)->create([ + 'email' => 'taylor@laravel.com', + ]); + + $this->browse(function ($browser) use ($user) { + $browser->loginAs($user) + ->visit('/home') + ->press('Create Playlist') + ->whenAvailable('.playlist-modal', function ($modal) { + $modal->type('name', 'My Playlist') + ->press('Create'); + }); + + $browser->waitForText('Playlist Created'); + }); + } + +For more information on Dusk, consult the full [Dusk documentation](/docs/5.4/dusk). + +### Laravel Mix + +> {video} There is a free [video tutorial](https://laracasts.com/series/whats-new-in-laravel-5-4/episodes/3) for this feature available on Laracasts. + +Laravel Mix is the spiritual successor of Laravel Elixir, and its entirely based on Webpack instead of Gulp. Laravel Mix provides a fluent API for defining Webpack build steps for your Laravel application using several common CSS and JavaScript pre-processors. Through simple method chaining, you can fluently define your asset pipeline. For example: + + mix.js('resources/assets/js/app.js', 'public/js') + .sass('resources/assets/sass/app.scss', 'public/css'); + +### Blade Components & Slots + +> {video} There is a free [video tutorial](https://laracasts.com/series/whats-new-in-laravel-5-4/episodes/6) for this feature available on Laracasts. + +Blade components and slots provide similar benefits to sections and layouts; however, some may find the mental model of components and slots easier to understand. First, let's imagine a reusable "alert" component we would like to reuse throughout our application: + + + +
    + {{ $slot }} +
    + +The `{{ $slot }}` variable will contain the content we wish to inject into the component. Now, to construct this component, we can use the `@component` Blade directive: + + @component('alert') + Whoops! Something went wrong! + @endcomponent + +Named slots allow you to provide multiple slots into a single component: + + + +
    +
    {{ $title }}
    + + {{ $slot }} +
    + +Named slots may be injected using the `@slot` directive. Any content is not within a `@slot` directive will be passed to the component in the `$slot` variable: + + @component('alert') + @slot('title') + Forbidden + @endslot + + You are not allowed to access this resource! + @endcomponent + +To read more about components and slots, consult the full [Blade documentation](/docs/5.4/blade). + +### Broadcast Model Binding + +Just like HTTP routes, channel routes may now take advantage of implicit and explicit [route model binding](/docs/5.4/routing#route-model-binding). For example, instead of receiving the string or numeric order ID, you may request an actual `Order` model instance: + + use App\Order; + + Broadcast::channel('order.{order}', function ($user, Order $order) { + return $user->id === $order->user_id; + }); + +To read more about broadcast model binding, consult the full [event broadcasting](/docs/5.4/broadcasting) documentation. + +### Collection Higher Order Messages + +> {video} There is a free [video tutorial](https://laracasts.com/series/whats-new-in-laravel-5-4/episodes/2) for this feature available on Laracasts. + +Collections now provide support for "higher order messages", which are short-cuts for performing common actions on collections. The collection methods that provide higher order messages are: `contains`, `each`, `every`, `filter`, `first`, `map`, `partition`, `reject`, `sortBy`, `sortByDesc`, and `sum`. + +Each higher order message can be accessed as a dynamic property on a collection instance. For instance, let's use the `each` higher order message to call a method on each object within a collection: + + $users = User::where('votes', '>', 500)->get(); + + $users->each->markAsVip(); + +Likewise, we can use the `sum` higher order message to gather the total number of "votes" for a collection of users: + + $users = User::where('group', 'Development')->get(); + + return $users->sum->votes; + +### Object Based Eloquent Events + +> {video} There is a free [video tutorial](https://laracasts.com/series/whats-new-in-laravel-5-4/episodes/10) for this feature available on Laracasts. + +Eloquent event handlers may now be mapped to event objects. This provides a more intuitive way of handling Eloquent events and makes it easier to test the events. To get started, define an `$events` property on your Eloquent model that maps various points of the Eloquent model's lifecycle to your own [event classes](/docs/5.4/events): + + UserSaved::class, + 'deleted' => UserDeleted::class, + ]; + } + +### Job Level Retry & Timeout + +Previously, queue job "retry" and "timeout" settings could only be configured globally for all jobs on the command line. However, in Laravel 5.4, these settings may be configured on a per-job basis by defining them directly on the job class: + + {video} There is a free [video tutorial](https://laracasts.com/series/whats-new-in-laravel-5-4/episodes/1) for this feature available on Laracasts. + +Laravel 5.4 includes two new middleware in the default middleware stack: `TrimStrings` and `ConvertEmptyStringsToNull`: + + /** + * The application's global HTTP middleware stack. + * + * These middleware are run during every request to your application. + * + * @var array + */ + protected $middleware = [ + \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class, + \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, + \App\Http\Middleware\TrimStrings::class, + \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, + ]; + +These middleware will automatically trim request input values and convert any empty strings to `null`. This helps you normalize the input for every request entering into your application and not have to worry about continually calling the `trim` function in every route and controller. + +### "Realtime" Facades + +> {video} There is a free [video tutorial](https://laracasts.com/series/whats-new-in-laravel-5-4/episodes/8) for this feature available on Laracasts. + +Previously, only Laravel's own built-in services exposed [facades](/docs/5.4/facades), which provide quick, terse access to their methods via the service container. However, in Laravel 5.4, you may easily convert any of your application's classes into a facade in realtime simply by prefixing the imported class name with `Facades`. For example, imagine your application contains a class like the following: + + tax = $tax; + } + + /** + * Pay the given amount. + * + * @param int $amount + * @return void + */ + public function pay($amount) + { + // Pay an amount... + } + } + +You may easily use this class as a facade like so: + + use Facades\ { + App\Services\PaymentGateway + }; + + Route::get('/pay/{amount}', function ($amount) { + PaymentGateway::pay($amount); + }); + +Of course, if you leverage a realtime facade in this way, you may easily write a test for the interaction using Laravel's [facade mocking capabilities](/docs/5.4/mocking): + + PaymentGateway::shouldReceive('pay')->with('100'); + +### Custom Pivot Table Models + +In Laravel 5.3, all "pivot" table models for `belongsToMany` relationships used the same built-in `Pivot` model instance. In Laravel 5.4, you may define custom models for your pivot tables. If you would like to define a custom model to represent the intermediate table of your relationship, use the `using` method when defining the relationship: + + belongsToMany('App\User')->using('App\UserRole'); + } + } + +### Improved Redis Cluster Support + +Previously, it was not possible to define Redis connections to single hosts and to clusters in the same application. In Laravel 5.4, you may now define Redis connections to multiple single hosts and multiple clusters within the same application. For more information on Redis in Laravel, please consult the full [Redis documentation](/docs/5.4/redis). + + +### Migration Default String Length + +Laravel 5.4 uses the `utf8mb4` character set by default, which includes support for storing "emojis" in the database. If you are upgrading your application from Laravel 5.3, you are not required to switch to this character set. + +If you choose to switch to this character set manually and are running a version of MySQL older than the 5.7.7 release, you may need to manually configure the default string length generated by migrations. You may configure this by calling the `Schema::defaultStringLength` method within your `AppServiceProvider`: + + use Illuminate\Support\Facades\Schema; + + /** + * Bootstrap any application services. + * + * @return void + */ + public function boot() + { + Schema::defaultStringLength(191); + } + + +## Laravel 5.3 + +Laravel 5.3 continues the improvements made in Laravel 5.2 by adding a driver based [notification system](/docs/5.3/notifications), robust realtime support via [Laravel Echo](/docs/5.3/broadcasting), painless OAuth2 servers via [Laravel Passport](/docs/5.3/passport), full-text model searching via [Laravel Scout](/docs/5.3/scout), Webpack support in Laravel Elixir, "mailable" objects, explicit separation of `web` and `api` routes, Closure based console commands, convenient helpers for storing uploaded files, support for POPO and single-action controllers, improved default frontend scaffolding, and more. + +### Notifications + +> {video} There is a free [video tutorial](https://laracasts.com/series/whats-new-in-laravel-5-3/episodes/9) for this feature available on Laracasts. + +Laravel Notifications provide a simple, expressive API for sending notifications across a variety of delivery channels such as email, Slack, SMS, and more. For example, you may define a notification that an invoice has been paid and deliver that notification via email and SMS. Then, you may send the notification using a single, simple method: + + $user->notify(new InvoicePaid($invoice)); + +There is already a wide variety of [community written drivers](http://laravel-notification-channels.com) for notifications, including support for iOS and Android notifications. To learn more about notifications, be sure to check out the [full notification documentation](/docs/5.3/notifications). + +### WebSockets / Event Broadcasting + +While event broadcasting existed in previous versions of Laravel, the Laravel 5.3 release greatly improves this feature of the framework by adding channel-level authentication for private and presence WebSocket channels: + + /* + * Authenticate the channel subscription... + */ + Broadcast::channel('orders.*', function ($user, $orderId) { + return $user->placedOrder($orderId); + }); + +Laravel Echo, a new JavaScript package installable via NPM, has also been released to provide a simple, beautiful API for subscribing to channels and listening for your server-side events in your client-side JavaScript application. Echo includes support for [Pusher](https://pusher.com) and [Socket.io](http://socket.io): + + Echo.channel('orders.' + orderId) + .listen('ShippingStatusUpdated', (e) => { + console.log(e.description); + }); + +In addition to subscribing to traditional channels, Laravel Echo also makes it a breeze to subscribe to presence channels which provide information about who is listening on a given channel: + + Echo.join('chat.' + roomId) + .here((users) => { + // + }) + .joining((user) => { + console.log(user.name); + }) + .leaving((user) => { + console.log(user.name); + }); + +To learn more about Echo and event broadcasting, check out the [full documentation](/docs/5.3/broadcasting). + +### Laravel Passport (OAuth2 Server) + +> {video} There is a free [video tutorial](https://laracasts.com/series/whats-new-in-laravel-5-3/episodes/13) for this feature available on Laracasts. + +Laravel 5.3 makes API authentication a breeze using [Laravel Passport](/docs/{{version}}/passport), which provides a full OAuth2 server implementation for your Laravel application in a matter of minutes. Passport is built on top of the [League OAuth2 server](https://github.com/thephpleague/oauth2-server) that is maintained by Alex Bilbie. + +Passport makes it painless to issue access tokens via OAuth2 authorization codes. You may also allow your users to create "personal access tokens" via your web UI. To get you started quickly, Passport includes [Vue components](https://vuejs.org) that can serve as a starting point for your OAuth2 dashboard, allowing users to create clients, revoke access tokens, and more: + + + + + +If you do not want to use the Vue components, you are welcome to provide your own frontend dashboard for managing clients and access tokens. Passport exposes a simple JSON API that you may use with any JavaScript framework you choose. + +Of course, Passport also makes it simple to define access token scopes that may be requested by application's consuming your API: + + Passport::tokensCan([ + 'place-orders' => 'Place new orders', + 'check-status' => 'Check order status', + ]); + +In addition, Passport includes helpful middleware for verifying that an access token authenticated request contains the necessary token scopes: + + Route::get('/orders/{order}/status', function (Order $order) { + // Access token has "check-status" scope... + })->middleware('scope:check-status'); + +Lastly, Passport includes support for consuming your own API from your JavaScript application without worrying about passing access tokens. Passport achieves this through encrypted JWT cookies and synchronized CSRF tokens, allowing you to focus on what matters: your application. For more information on Passport, be sure to check out its [full documentation](/docs/5.3/passport). + +### Search (Laravel Scout) + +Laravel Scout provides a simple, driver based solution for adding full-text search to your [Eloquent models](/docs/5.3/eloquent). Using model observers, Scout will automatically keep your search indexes in sync with your Eloquent records. Currently, Scout ships with an [Algolia](https://www.algolia.com/) driver; however, writing custom drivers is simple and you are free to extend Scout with your own search implementations. + +Making models searchable is as simple as adding a `Searchable` trait to the model: + + save(); + +Once your models have been indexed, its a breeze to perform full-text searches across all of your models. You may even paginate your search results: + + return Order::search('Star Trek')->get(); + + return Order::search('Star Trek')->where('user_id', 1)->paginate(); + +Of course, Scout has many more features which are covered in the [full documentation](/docs/5.3/scout). + +### Mailable Objects + +> {video} There is a free [video tutorial](https://laracasts.com/series/whats-new-in-laravel-5-3/episodes/6) for this feature available on Laracasts. + +Laravel 5.3 ships with support for mailable objects. These objects allow you to represent your email messages as a simple objects instead of customizing mail messages within Closures. For example, you may define a simple mailable object for a "welcome" email: + + class WelcomeMessage extends Mailable + { + use Queueable, SerializesModels; + + /** + * Build the message. + * + * @return $this + */ + public function build() + { + return $this->view('emails.welcome'); + } + } + +Once the mailable object has been defined, you can send it to a user using a simple, expressive API. Mailable objects are great for discovering the intent of your messages while scanning your code: + + Mail::to($user)->send(new WelcomeMessage); + +Of course, you may also mark mailable objects as "queueable" so that they will be sent in the background by your queue workers: + + class WelcomeMessage extends Mailable implements ShouldQueue + { + // + } + +For more information on mailable objects, be sure to check out the [mail documentation](/docs/5.3/mail). + +### Storing Uploaded Files + +> {video} There is a free [video tutorial](https://laracasts.com/series/whats-new-in-laravel-5-3/episodes/12) for this feature available on Laracasts. + +In web applications, one of the most common use-cases for storing files is storing user uploaded files such as profile pictures, photos, and documents. Laravel 5.3 makes it very easy to store uploaded files using the new `store` method on an uploaded file instance. Simply call the `store` method with the path at which you wish to store the uploaded file: + + /** + * Update the avatar for the user. + * + * @param Request $request + * @return Response + */ + public function update(Request $request) + { + $path = $request->file('avatar')->store('avatars', 's3'); + + return $path; + } + +For more information on storing uploaded files, check out the [full documentation](/docs/{{version}}/filesystem#file-uploads). + + +### Webpack & Laravel Elixir + +Along with Laravel 5.3, Laravel Elixir 6.0 has been released with baked-in support for the Webpack and Rollup JavaScript module bundlers. By default, the Laravel 5.3 `gulpfile.js` file now uses Webpack to compile your JavaScript. The [full Laravel Elixir documentation](/docs/5.3/elixir) contains more information on both of these bundlers: + + elixir(mix => { + mix.sass('app.scss') + .webpack('app.js'); + }); + +### Frontend Structure + +> {video} There is a free [video tutorial](https://laracasts.com/series/whats-new-in-laravel-5-3/episodes/4) for this feature available on Laracasts. + +Laravel 5.3 ships with a more modern frontend structure. This primarily affects the `make:auth` authentication scaffolding. Instead of loading frontend assets from a CDN, dependencies are specified in the default `package.json` file. + +In addition, support for single file [Vue components](https://vuejs.org) is now included out of the box. A sample `Example.vue` component is included in the `resources/assets/js/components` directory. In addition, the new `resources/assets/js/app.js` file bootstraps and configures your JavaScript libraries and, if applicable, Vue components. + +This structure provides more guidance on how to begin developing modern, robust JavaScript applications, without requiring your application to use any given JavaScript or CSS framework. For more information on getting started with modern Laravel frontend development, check out the new [introductory frontend documentation](/docs/5.3/frontend). + +### Routes Files + +By default, fresh Laravel 5.3 applications contain two HTTP route files in a new top-level `routes` directory. The `web` and `api` route files provide more explicit guidance in how to split the routes for your web interface and your API. The routes in the `api` route file are automatically assigned the `api` prefix by the `RouteServiceProvider`. + +### Closure Console Commands + +In addition to being defined as command classes, Artisan commands may now be defined as simple Closures in the `commands` method of your `app/Console/Kernel.php` file. In fresh Laravel 5.3 applications, the `commands` method loads a `routes/console.php` file which allows you to define your Console commands as route-like, Closure based entry points into your application: + + Artisan::command('build {project}', function ($project) { + $this->info('Building project...'); + }); + +For more information on Closure commands, check out the [full Artisan documentation](/docs/5.3/artisan#closure-commands). + +### The `$loop` Variable + +> {video} There is a free [video tutorial](https://laracasts.com/series/whats-new-in-laravel-5-3/episodes/7) for this feature available on Laracasts. + +When looping within a Blade template, a `$loop` variable will be available inside of your loop. This variable provides access to some useful bits of information such as the current loop index and whether this is the first or last iteration through the loop: + + @foreach ($users as $user) + @if ($loop->first) + This is the first iteration. + @endif + + @if ($loop->last) + This is the last iteration. + @endif + +

    This is user {{ $user->id }}

    + @endforeach + +For more information, consult the [full Blade documentation](/docs/5.3/blade#the-loop-variable). + + +## Laravel 5.2 + +Laravel 5.2 continues the improvements made in Laravel 5.1 by adding multiple authentication driver support, implicit model binding, simplified Eloquent global scopes, opt-in authentication scaffolding, middleware groups, rate limiting middleware, array validation improvements, and more. + +### Authentication Drivers / "Multi-Auth" + +In previous versions of Laravel, only the default, session-based authentication driver was supported out of the box, and you could not have more than one authenticatable model instance per application. + +However, in Laravel 5.2, you may define additional authentication drivers as well define multiple authenticatable models or user tables, and control their authentication process separately from each other. For example, if your application has one database table for "admin" users and one database table for "student" users, you may now use the `Auth` methods to authenticate against each of these tables separately. + +### Authentication Scaffolding + +Laravel already makes it easy to handle authentication on the back-end; however, Laravel 5.2 provides a convenient, lightning-fast way to scaffold the authentication views for your front-end. Simply execute the `make:auth` command on your terminal: + + php artisan make:auth + +This command will generate plain, Bootstrap compatible views for user login, registration, and password reset. The command will also update your routes file with the appropriate routes. + +> {note} This feature is only meant to be used on new applications, not during application upgrades. + +### Implicit Model Binding + +Implicit model binding makes it painless to inject relevant models directly into your routes and controllers. For example, assume you have a route defined like the following: + + use App\User; + + Route::get('/user/{user}', function (User $user) { + return $user; + }); + +In Laravel 5.1, you would typically need to use the `Route::model` method to instruct Laravel to inject the `App\User` instance that matches the `{user}` parameter in your route definition. However, in Laravel 5.2, the framework will **automatically** inject this model based on the URI segment, allowing you to quickly gain access to the model instances you need. + +Laravel will automatically inject the model when the route parameter segment (`{user}`) matches the route Closure or controller method's corresponding variable name (`$user`) and the variable is type-hinting an Eloquent model class. + +### Middleware Groups + +Middleware groups allow you to group several route middleware under a single, convenient key, allowing you to assign several middleware to a route at once. For example, this can be useful when building a web UI and an API within the same application. You may group the session and CSRF routes into a `web` group, and perhaps the rate limiter in the `api` group. + +In fact, the default Laravel 5.2 application structure takes exactly this approach. For example, in the default `App\Http\Kernel.php` file you will find the following: + + /** + * The application's route middleware groups. + * + * @var array + */ + protected $middlewareGroups = [ + 'web' => [ + \App\Http\Middleware\EncryptCookies::class, + \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, + \Illuminate\Session\Middleware\StartSession::class, + \Illuminate\View\Middleware\ShareErrorsFromSession::class, + \App\Http\Middleware\VerifyCsrfToken::class, + ], + + 'api' => [ + 'throttle:60,1', + ], + ]; + +Then, the `web` group may be assigned to routes like so: + + Route::group(['middleware' => ['web']], function () { + // + }); + +However, keep in mind the `web` middleware group is *already* applied to your routes by default since the `RouteServiceProvider` includes it in the default middleware group. + +### Rate Limiting + +A new rate limiter middleware is now included with the framework, allowing you to easily limit the number of requests that a given IP address can make to a route over a specified number of minutes. For example, to limit a route to 60 requests every minute from a single IP address, you may do the following: + + Route::get('/api/users', ['middleware' => 'throttle:60,1', function () { + // + }]); + +### Array Validation + +Validating array form input fields is much easier in Laravel 5.2. For example, to validate that each e-mail in a given array input field is unique, you may do the following: + + $validator = Validator::make($request->all(), [ + 'person.*.email' => 'email|unique:users' + ]); + +Likewise, you may use the `*` character when specifying your validation messages in your language files, making it a breeze to use a single validation message for array based fields: + + 'custom' => [ + 'person.*.email' => [ + 'unique' => 'Each person must have a unique e-mail address', + ] + ], + +### Bail Validation Rule + +A new `bail` validation rule has been added, which instructs the validator to stop validating after the first validation failure for a given rule. For example, you may now prevent the validator from running a `unique` check if an attribute fails an `integer` check: + + $this->validate($request, [ + 'user_id' => 'bail|integer|unique:users' + ]); + +### Eloquent Global Scope Improvements + +In previous versions of Laravel, global Eloquent scopes were complicated and error-prone to implement; however, in Laravel 5.2, global query scopes only require you to implement a single, simple method: `apply`. + +For more information on writing global scopes, check out the full [Eloquent documentation](/docs/{{version}}/eloquent#global-scopes). + + +## Laravel 5.1.11 + +Laravel 5.1.11 introduces [authorization](/docs/{{version}}/authorization) support out of the box! Conveniently organize your application's authorization logic using simple callbacks or policy classes, and authorize actions using simple, expressive methods. + +For more information, please refer to the [authorization documentation](/docs/{{version}}/authorization). + + +## Laravel 5.1.4 + +Laravel 5.1.4 introduces simple login throttling to the framework. Consult the [authentication documentation](/docs/{{version}}/authentication#authentication-throttling) for more information. + + +## Laravel 5.1 + +Laravel 5.1 continues the improvements made in Laravel 5.0 by adopting PSR-2 and adding event broadcasting, middleware parameters, Artisan improvements, and more. + +### PHP 5.5.9+ + +Since PHP 5.4 will enter "end of life" in September and will no longer receive security updates from the PHP development team, Laravel 5.1 requires PHP 5.5.9 or greater. PHP 5.5.9 allows compatibility with the latest versions of popular PHP libraries such as Guzzle and the AWS SDK. + +### LTS + + Laravel 5.1 is the first release of Laravel to receive **long term support**. Laravel 5.1 will receive bug fixes for 2 years and security fixes for 3 years. This support window is the largest ever provided for Laravel and provides stability and peace of mind for larger, enterprise clients and customers. + +### PSR-2 + +The [PSR-2 coding style guide](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) has been adopted as the default style guide for the Laravel framework. Additionally, all generators have been updated to generate PSR-2 compatible syntax. + +### Documentation + +Every page of the Laravel documentation has been meticulously reviewed and dramatically improved. All code examples have also been reviewed and expanded to provide more relevance and context. + +### Event Broadcasting + +In many modern web applications, web sockets are used to implement realtime, live-updating user interfaces. When some data is updated on the server, a message is typically sent over a websocket connection to be handled by the client. + +To assist you in building these types of applications, Laravel makes it easy to "broadcast" your events over a websocket connection. Broadcasting your Laravel events allows you to share the same event names between your server-side code and your client-side JavaScript framework. + +To learn more about event broadcasting, check out the [event documentation](/docs/{{version}}/events#broadcasting-events). + +### Middleware Parameters + +Middleware can now receive additional custom parameters. For example, if your application needs to verify that the authenticated user has a given "role" before performing a given action, you could create a `RoleMiddleware` that receives a role name as an additional argument: + + user()->hasRole($role)) { + // Redirect... + } + + return $next($request); + } + + } + +Middleware parameters may be specified when defining the route by separating the middleware name and parameters with a `:`. Multiple parameters should be delimited by commas: + + Route::put('post/{id}', ['middleware' => 'role:editor', function ($id) { + // + }]); + +For more information on middleware, check out the [middleware documentation](/docs/{{version}}/middleware). + +### Testing Overhaul + +The built-in testing capabilities of Laravel have been dramatically improved. A variety of new methods provide a fluent, expressive interface for interacting with your application and examining its responses. For example, check out the following test: + + public function testNewUserRegistration() + { + $this->visit('/register') + ->type('Taylor', 'name') + ->check('terms') + ->press('Register') + ->seePageIs('/dashboard'); + } + +For more information on testing, check out the [testing documentation](/docs/{{version}}/testing). + +### Model Factories + +Laravel now ships with an easy way to create stub Eloquent models using [model factories](/docs/{{version}}/database-testing#writing-factories). Model factories allow you to easily define a set of "default" attributes for your Eloquent model, and then generate test model instances for your tests or database seeds. Model factories also take advantage of the powerful [Faker](https://github.com/fzaninotto/Faker) PHP library for generating random attribute data: + + $factory->define(App\User::class, function ($faker) { + return [ + 'name' => $faker->name, + 'email' => $faker->email, + 'password' => str_random(10), + 'remember_token' => str_random(10), + ]; + }); + +For more information on model factories, check out [the documentation](/docs/{{version}}/database-testing#writing-factories). + +### Artisan Improvements + +Artisan commands may now be defined using a simple, route-like "signature", which provides an extremely simple interface for defining command line arguments and options. For example, you may define a simple command and its options like so: + + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'email:send {user} {--force}'; + +For more information on defining Artisan commands, consult the [Artisan documentation](/docs/{{version}}/artisan). + +### Folder Structure + +To better express intent, the `app/Commands` directory has been renamed to `app/Jobs`. Additionally, the `app/Handlers` directory has been consolidated into a single `app/Listeners` directory which simply contains event listeners. However, this is not a breaking change and you are not required to update to the new folder structure to use Laravel 5.1. + +### Encryption + +In previous versions of Laravel, encryption was handled by the `mcrypt` PHP extension. However, beginning in Laravel 5.1, encryption is handled by the `openssl` extension, which is more actively maintained. + + +## Laravel 5.0 + +Laravel 5.0 introduces a fresh application structure to the default Laravel project. This new structure serves as a better foundation for building a robust application in Laravel, as well as embraces new auto-loading standards (PSR-4) throughout the application. First, let's examine some of the major changes: + +### New Folder Structure + +The old `app/models` directory has been entirely removed. Instead, all of your code lives directly within the `app` folder, and, by default, is organized to the `App` namespace. This default namespace can be quickly changed using the new `app:name` Artisan command. + +Controllers, middleware, and requests (a new type of class in Laravel 5.0) are now grouped under the `app/Http` directory, as they are all classes related to the HTTP transport layer of your application. Instead of a single, flat file of route filters, all middleware are now broken into their own class files. + +A new `app/Providers` directory replaces the `app/start` files from previous versions of Laravel 4.x. These service providers provide various bootstrapping functions to your application, such as error handling, logging, route loading, and more. Of course, you are free to create additional service providers for your application. + +Application language files and views have been moved to the `resources` directory. + +### Contracts + +All major Laravel components implement interfaces which are located in the `illuminate/contracts` repository. This repository has no external dependencies. Having a convenient, centrally located set of interfaces you may use for decoupling and dependency injection will serve as an easy alternative option to Laravel Facades. + +For more information on contracts, consult the [full documentation](/docs/{{version}}/contracts). + +### Route Cache + +If your application is made up entirely of controller routes, you may utilize the new `route:cache` Artisan command to drastically speed up the registration of your routes. This is primarily useful on applications with 100+ routes and will **drastically** speed up this portion of your application. + +### Route Middleware + +In addition to Laravel 4 style route "filters", Laravel 5 now supports HTTP middleware, and the included authentication and CSRF "filters" have been converted to middleware. Middleware provides a single, consistent interface to replace all types of filters, allowing you to easily inspect, and even reject, requests before they enter your application. + +For more information on middleware, check out [the documentation](/docs/{{version}}/middleware). + +### Controller Method Injection + +In addition to the existing constructor injection, you may now type-hint dependencies on controller methods. The [service container](/docs/{{version}}/container) will automatically inject the dependencies, even if the route contains other parameters: + + public function createPost(Request $request, PostRepository $posts) + { + // + } + +### Authentication Scaffolding + +User registration, authentication, and password reset controllers are now included out of the box, as well as simple corresponding views, which are located at `resources/views/auth`. In addition, a "users" table migration has been included with the framework. Including these simple resources allows rapid development of application ideas without bogging down on authentication boilerplate. The authentication views may be accessed on the `auth/login` and `auth/register` routes. The `App\Services\Auth\Registrar` service is responsible for user validation and creation. + +### Event Objects + +You may now define events as objects instead of simply using strings. For example, check out the following event: + + podcast = $podcast; + } + } + +The event may be dispatched like normal: + + Event::fire(new PodcastWasPurchased($podcast)); + +Of course, your event handler will receive the event object instead of a list of data: + + user = $user; + $this->podcast = $podcast; + } + + /** + * Execute the command. + * + * @return void + */ + public function handle() + { + // Handle the logic to purchase the podcast... + + event(new PodcastWasPurchased($this->user, $this->podcast)); + } + } + +The base Laravel controller utilizes the new `DispatchesCommands` trait, allowing you to easily dispatch your commands for execution: + + $this->dispatch(new PurchasePodcastCommand($user, $podcast)); + +Of course, you may also use commands for tasks that are executed synchronously (are not queued). In fact, using commands is a great way to encapsulate complex tasks your application needs to perform. For more information, check out the [command bus](/docs/{{version}}/bus) documentation. + +### Database Queue + +A `database` queue driver is now included in Laravel, providing a simple, local queue driver that requires no extra package installation beyond your database software. + +### Laravel Scheduler + +In the past, developers have generated a Cron entry for each console command they wished to schedule. However, this is a headache. Your console schedule is no longer in source control, and you must SSH into your server to add the Cron entries. Let's make our lives easier. The Laravel command scheduler allows you to fluently and expressively define your command schedule within Laravel itself, and only a single Cron entry is needed on your server. + +It looks like this: + + $schedule->command('artisan:command')->dailyAt('15:00'); + +Of course, check out the [full documentation](/docs/{{version}}/scheduling) to learn all about the scheduler! + +### Tinker / Psysh + +The `php artisan tinker` command now utilizes [Psysh](https://github.com/bobthecow/psysh) by Justin Hileman, a more robust REPL for PHP. If you liked Boris in Laravel 4, you're going to love Psysh. Even better, it works on Windows! To get started, just try: + + php artisan tinker + +### DotEnv + +Instead of a variety of confusing, nested environment configuration directories, Laravel 5 now utilizes [DotEnv](https://github.com/vlucas/phpdotenv) by Vance Lucas. This library provides a super simple way to manage your environment configuration, and makes environment detection in Laravel 5 a breeze. For more details, check out the full [configuration documentation](/docs/{{version}}/installation#environment-configuration). + +### Laravel Elixir + +Laravel Elixir, by Jeffrey Way, provides a fluent, expressive interface to compiling and concatenating your assets. If you've ever been intimidated by learning Grunt or Gulp, fear no more. Elixir makes it a cinch to get started using Gulp to compile your Less, Sass, and CoffeeScript. It can even run your tests for you! + +For more information on Elixir, check out the [full documentation](/docs/{{version}}/elixir). + +### Laravel Socialite + +Laravel Socialite is an optional, Laravel 5.0+ compatible package that provides totally painless authentication with OAuth providers. Currently, Socialite supports Facebook, Twitter, Google, and GitHub. Here's what it looks like: + + public function redirectForAuth() + { + return Socialize::with('twitter')->redirect(); + } + + public function getUserFromProvider() + { + $user = Socialize::with('twitter')->user(); + } + +No more spending hours writing OAuth authentication flows. Get started in minutes! The [full documentation](/docs/{{version}}/authentication#social-authentication) has all the details. + +### Flysystem Integration + +Laravel now includes the powerful [Flysystem](https://github.com/thephpleague/flysystem) filesystem abstraction library, providing pain free integration with local, Amazon S3, and Rackspace cloud storage - all with one, unified and elegant API! Storing a file in Amazon S3 is now as simple as: + + Storage::put('file.txt', 'contents'); + +For more information on the Laravel Flysystem integration, consult the [full documentation](/docs/{{version}}/filesystem). + +### Form Requests + +Laravel 5.0 introduces **form requests**, which extend the `Illuminate\Foundation\Http\FormRequest` class. These request objects can be combined with controller method injection to provide a boiler-plate free method of validating user input. Let's dig in and look at a sample `FormRequest`: + + 'required|email|unique:users', + 'password' => 'required|confirmed|min:8', + ]; + } + + public function authorize() + { + return true; + } + } + +Once the class has been defined, we can type-hint it on our controller action: + + public function register(RegisterRequest $request) + { + var_dump($request->input()); + } + +When the Laravel service container identifies that the class it is injecting is a `FormRequest` instance, the request will **automatically be validated**. This means that if your controller action is called, you can safely assume the HTTP request input has been validated according to the rules you specified in your form request class. Even more, if the request is invalid, an HTTP redirect, which you may customize, will automatically be issued, and the error messages will be either flashed to the session or converted to JSON. **Form validation has never been more simple.** For more information on `FormRequest` validation, check out the [documentation](/docs/{{version}}/validation#form-request-validation). + +### Simple Controller Request Validation + +The Laravel 5 base controller now includes a `ValidatesRequests` trait. This trait provides a simple `validate` method to validate incoming requests. If `FormRequests` are a little too much for your application, check this out: + + public function createPost(Request $request) + { + $this->validate($request, [ + 'title' => 'required|max:255', + 'body' => 'required', + ]); + } + +If the validation fails, an exception will be thrown and the proper HTTP response will automatically be sent back to the browser. The validation errors will even be flashed to the session! If the request was an AJAX request, Laravel even takes care of sending a JSON representation of the validation errors back to you. + +For more information on this new method, check out [the documentation](/docs/{{version}}/validation#validation-quickstart). + +### New Generators + +To complement the new default application structure, new Artisan generator commands have been added to the framework. See `php artisan list` for more details. + +### Configuration Cache + +You may now cache all of your configuration in a single file using the `config:cache` command. + +### Symfony VarDumper + +The popular `dd` helper function, which dumps variable debug information, has been upgraded to use the amazing Symfony VarDumper. This provides color-coded output and even collapsing of arrays. Just try the following in your project: + + dd([1, 2, 3]); + ## Laravel 4.2 The full change list for this release by running the `php artisan changes` command from a 4.2 installation, or by [viewing the change file on Github](https://github.com/laravel/framework/blob/4.2/src/Illuminate/Foundation/changes.json). These notes only cover the major enhancements and changes for the release. -> **Note:** During the 4.2 release cycle, many small bug fixes and enhancements were incorporated into the various Laravel 4.1 point releases. So, be sure to check the change list for Laravel 4.1 as well! +> {note} During the 4.2 release cycle, many small bug fixes and enhancements were incorporated into the various Laravel 4.1 point releases. So, be sure to check the change list for Laravel 4.1 as well! ### PHP 5.4 Requirement -Laravel 4.2 requires PHP 5.4 or greater. This PHP upgrade requirements allows us to use new PHP features such as traits to provide a more expressive interfaces for tools like [Laravel Cashier](billing.md). PHP 5.4 also brings significant speed and performance improvements over PHP 5.3. +Laravel 4.2 requires PHP 5.4 or greater. This upgraded PHP requirement allows us to use new PHP features such as traits to provide more expressive interfaces for tools like [Laravel Cashier](/docs/billing). PHP 5.4 also brings significant speed and performance improvements over PHP 5.3. ### Laravel Forge @@ -24,11 +1057,11 @@ More information about Laravel Forge can be found on the [official Forge website ### Laravel Homestead -Laravel Homestead is an official Vagrant environment for developing robust Laravel and PHP applications. The vast majority of the boxes provisioning needs are handled before the box is packaged for distribution, allowing the box to boot extremely quickly. Homestead includes Nginx 1.6, PHP 5.5.12, MySQL, Postgres, Redis, Memcached, Beanstalk, Node, Gulp, Grunt, & Bower. Homestaed includes a simple `Homestead.yaml` configuration file or managing multiple Laravel applications on a single box. +Laravel Homestead is an official Vagrant environment for developing robust Laravel and PHP applications. The vast majority of the boxes' provisioning needs are handled before the box is packaged for distribution, allowing the box to boot extremely quickly. Homestead includes Nginx 1.6, PHP 5.6, MySQL, Postgres, Redis, Memcached, Beanstalk, Node, Gulp, Grunt, & Bower. Homestead includes a simple `Homestead.yaml` configuration file for managing multiple Laravel applications on a single box. The default Laravel 4.2 installation now includes an `app/config/local/database.php` configuration file that is configured to use the Homestead database out of the box, making Laravel initial installation and configuration more convenient. -The official documentation has also been updated to include [Homestead documentation](homestead.md). +The official documentation has also been updated to include [Homestead documentation](/docs/homestead). ### Laravel Cashier @@ -36,9 +1069,9 @@ Laravel Cashier is a simple, expressive library for managing subscription billin ### Daemon Queue Workers -The Artisan `queue:work` command now supports a `--daemon` option to start a worker in "deamon mode", meaning the worker will continue to process jobs without ever re-booting the framework. This results in a significant reduction in CPU usage at the cost of a slightly more complex application deployment process. +The Artisan `queue:work` command now supports a `--daemon` option to start a worker in "daemon mode", meaning the worker will continue to process jobs without ever re-booting the framework. This results in a significant reduction in CPU usage at the cost of a slightly more complex application deployment process. -More information about daemon queue workers can be found in the [queue documentation](queue#daemon-queue-workers.md). +More information about daemon queue workers can be found in the [queue documentation](/docs/queues#daemon-queue-worker). ### Mail API Drivers @@ -48,7 +1081,7 @@ Laravel 4.2 introduces new Mailgun and Mandrill API drivers for the `Mail` funct A much cleaner architecture for "soft deletes" and other "global scopes" has been introduced via PHP 5.4 traits. This new architecture allows for the easier construction of similar global traits, and a cleaner separation of concerns within the framework itself. -More information on the new `SoftDeletingTrait` may be found in the [Eloquent documentation](eloquent#soft-deleting.md). +More information on the new `SoftDeletingTrait` may be found in the [Eloquent documentation](/docs/eloquent#soft-deleting). ### Convenient Auth & Remindable Traits @@ -71,7 +1104,7 @@ The full change list for this release by running the `php artisan changes` comma ### New SSH Component -An entirely new `SSH` component has been introduced with this release. This feature allows you to easily SSH into remote servers and run commands. To learn more, consult the [SSH component documentation](ssh.md). +An entirely new `SSH` component has been introduced with this release. This feature allows you to easily SSH into remote servers and run commands. To learn more, consult the [SSH component documentation](/docs/ssh). The new `php artisan tail` command utilizes the new SSH component. For more information, consult the `tail` [command documentation](http://laravel.com/docs/ssh#tailing-remote-logs). @@ -81,13 +1114,13 @@ The `php artisan tinker` command now utilizes the [Boris REPL](https://github.co ### Eloquent Improvements -A new `hasManyThrough` relationship has been added to Eloquent. To learn how to use it, consult the [Eloquent documentation](eloquent#has-many-through.md). +A new `hasManyThrough` relationship has been added to Eloquent. To learn how to use it, consult the [Eloquent documentation](/docs/eloquent#has-many-through). -A new `whereHas` method has also been introduced to allow [retrieving models based on relationship constraints](eloquent#querying-relations.md). +A new `whereHas` method has also been introduced to allow [retrieving models based on relationship constraints](/docs/eloquent#querying-relations). ### Database Read / Write Connections -Automatic handling of separate read / write connections is now available throughout the database layer, including the query builder and Eloquent. For more information, consult [the documentation](database#read-write-connections.md). +Automatic handling of separate read / write connections is now available throughout the database layer, including the query builder and Eloquent. For more information, consult [the documentation](/docs/database#read-write-connections). ### Queue Priority @@ -95,15 +1128,15 @@ Queue priorities are now supported by passing a comma-delimited list to the `que ### Failed Queue Job Handling -The queue facilities now include automatic handling of failed jobs when using the new `--tries` switch on `queue:listen`. More information on handling failed jobs can be found in the [queue documentation](queues#failed-jobs.md). +The queue facilities now include automatic handling of failed jobs when using the new `--tries` switch on `queue:listen`. More information on handling failed jobs can be found in the [queue documentation](/docs/queues#failed-jobs). ### Cache Tags -Cache "sections" have been superseded by "tags". Cache tags allow you to assign multiple "tags" to a cache item, and flush all items assigned to a single tag. More information on using cache tags may be found in the [cache documentation](cache#cache-tags.md). +Cache "sections" have been superseded by "tags". Cache tags allow you to assign multiple "tags" to a cache item, and flush all items assigned to a single tag. More information on using cache tags may be found in the [cache documentation](/docs/cache#cache-tags). ### Flexible Password Reminders -The password reminder engine has been changed to provide greater developer flexibility when validating passwords, flashing status messages to the session, etc. For more information on using the enhanced password reminder engine, [consult the documentation](security#password-reminders-and-reset.md). +The password reminder engine has been changed to provide greater developer flexibility when validating passwords, flashing status messages to the session, etc. For more information on using the enhanced password reminder engine, [consult the documentation](/docs/security#password-reminders-and-reset). ### Improved Routing Engine @@ -115,4 +1148,4 @@ With this release, we're also introducing an entirely new session engine. Simila ### Doctrine DBAL -If you are using the `renameColumn` function in your migrations, you will need to add the `doctrine/dbal` dependency to your `composer.json` file. This package is no longer included in Laravel by default. \ No newline at end of file +If you are using the `renameColumn` function in your migrations, you will need to add the `doctrine/dbal` dependency to your `composer.json` file. This package is no longer included in Laravel by default. diff --git a/requests.md b/requests.md old mode 100755 new mode 100644 index 42b52f9..fa70a40 --- a/requests.md +++ b/requests.md @@ -1,224 +1,316 @@ -# Requests နှင့် Input များအကြောင်း - -- [Basic Input](#basic-input) -- [Cookies](#cookies) -- [Old Input](#old-input) +# HTTP Requests + +- [Accessing The Request](#accessing-the-request) + - [Request Path & Method](#request-path-and-method) + - [PSR-7 Requests](#psr7-requests) +- [Retrieving Input](#retrieving-input) + - [Old Input](#old-input) + - [Cookies](#cookies) - [Files](#files) -- [Request Information](#request-information) + - [Retrieving Uploaded Files](#retrieving-uploaded-files) + - [Storing Uploaded Files](#storing-uploaded-files) - -## Basic Input + +## Accessing The Request -You may access all user input with a few simple methods. You do not need to worry about the HTTP verb used for the request, as input is accessed in the same way for all verbs. +To obtain an instance of the current HTTP request via dependency injection, you should type-hint the `Illuminate\Http\Request` class on your controller method. The incoming request instance will automatically be injected by the [service container](/docs/{{version}}/container): -Http verb တွေအားလုံးက input ဆီကို ဝင်ရောက်လာတဲ့အချိန်မှာ Simple methods တွေနဲ့ users အားလုံးရဲ့ input တွေကို access လုပ်နိုင်ပါတယ်။ Request တွေအတွက် HTTP verb တွေကိုစိုးရိမ်စရာမလိုပါဘူး။ + input('name'); - $name = Input::get('name', 'Sally'); + // + } + } -#### Input Value ရှိတာကိုဆုံးဖြတ်ဖို့- +#### Dependency Injection & Route Parameters - if (Input::has('name')) - { - // - } +If your controller method is also expecting input from a route parameter you should list your route parameters after your other dependencies. For example, if your route is defined like so: -#### Input အားလုံးရဲ့ Request ကိုရချင်ရင်- + Route::put('user/{id}', 'UserController@update'); - $input = Input::all(); +You may still type-hint the `Illuminate\Http\Request` and access your route parameter `id` by defining your controller method as follows: -#### Input တစ်ချို့ရဲ့ Request အားလုံးကိုရချင်ရင်- + **Note:** Some JavaScript libraries such as Backbone may send input to the application as JSON. You may access this data via `Input::get` like normal. +You may also type-hint the `Illuminate\Http\Request` class on a route Closure. The service container will automatically inject the incoming request into the Closure when it is executed: - -## Cookies + use Illuminate\Http\Request; -Cookies အားလုံးကို Laravel Framework က authernication code နဲ့ encrypted လုပ်ထားပါတယ်၊ ဒါကဘာကိုဆိုလိုတာလဲဆိုရင် cookie တွေကို client ကပြောင်းလိုက်ပြီဆိုရင် သူတို့တရားမဝင်တာကိုနားလည်လိမ့်မယ်။ + Route::get('/', function (Request $request) { + // + }); -#### Cookie တစ်ခုရဲ့ Value ကိုရချင်ရင် + +### Request Path & Method - $value = Cookie::get('name'); +The `Illuminate\Http\Request` instance provides a variety of methods for examining the HTTP request for your application and extends the `Symfony\Component\HttpFoundation\Request` class. We will discuss a few of the most important methods below. -#### Response တစ်ခုဆီကို Cookie အသစ်တစ်ခု attach လုပ်ချင်ရင် - +#### Retrieving The Request Path - $response = Response::make('Hello World'); +The `path` method returns the request's path information. So, if the incoming request is targeted at `http://domain.com/foo/bar`, the `path` method will return `foo/bar`: - $response->withCookie(Cookie::make('name', 'value', $minutes)); + $uri = $request->path(); -#### နောက် Response တစ်ခုအတွက် Cookie တစ်ခုကို Queue လုပ်ခြင်း -Response မလုပ်ခင်မှာ cookie တစ်ခုကို set ချင်တယ်ဆို့င်ရင် `Cookie::queue()` method ကိုသုံးပါ။ သင့် application မှ နောက်ဆုံး response ကို cookie က အလိုလို attach လုပ်သွားပါလိမ့်မယ်။ +The `is` method allows you to verify that the incoming request path matches a given pattern. You may use the `*` character as a wildcard when utilizing this method: - Cookie::queue($name, $value, $minutes); + if ($request->is('admin/*')) { + // + } -#### Creating A Cookie That Lasts Forever +#### Retrieving The Request URL - $cookie = Cookie::forever('name', 'value'); +To retrieve the full URL for the incoming request you may use the `url` or `fullUrl` methods. The `url` method will return the URL without the query string, while the `fullUrl` method includes the query string: - -## Old Input + // Without Query String... + $url = $request->url(); -သင့်အနေနဲ့ request တစ်ခုကနေ တစ်ခု အကူးအပြောင်းအထိ input တွေကိုထိမ်းသိမ်းထားချင်ပါလိမ့်မယ်... ဥပမာ သင့်အနေနဲ့ form input တွေကို validation လုပ်ပြီး errors message နဲ့အတူ input တွေကိုပြန်ပြတဲ့ အချိန်မျိုးပေါ့။ + // With Query String... + $url = $request->fullUrl(); -#### Flashing Input To The Session +#### Retrieving The Request Method - Input::flash(); +The `method` method will return the HTTP verb for the request. You may use the `isMethod` method to verify that the HTTP verb matches a given string: -#### Flashing Only Some Input To The Session + $method = $request->method(); - Input::flashOnly('username', 'email'); + if ($request->isMethod('post')) { + // + } - Input::flashExcept('password'); + +### PSR-7 Requests -Since you often will want to flash input in association with a redirect to the previous page, you may easily chain input flashing onto a redirect. +The [PSR-7 standard](http://www.php-fig.org/psr/psr-7/) specifies interfaces for HTTP messages, including requests and responses. If you would like to obtain an instance of a PSR-7 request instead of a Laravel request, you will first need to install a few libraries. Laravel uses the *Symfony HTTP Message Bridge* component to convert typical Laravel requests and responses into PSR-7 compatible implementations: - return Redirect::to('form')->withInput(); + composer require symfony/psr-http-message-bridge + composer require zendframework/zend-diactoros - return Redirect::to('form')->withInput(Input::except('password')); +Once you have installed these libraries, you may obtain a PSR-7 request by type-hinting the request interface on your route Closure or controller method: -> **Note:** You may flash other data across requests using the [Session](session.md) class. + use Psr\Http\Message\ServerRequestInterface; -#### Input Data အဟောင်းတွေကိုပြန်ကြည့်ချင်ရင် - + Route::get('/', function (ServerRequestInterface $request) { + // + }); - Input::old('username'); +> {tip} If you return a PSR-7 response instance from a route or controller, it will automatically be converted back to a Laravel response instance and be displayed by the framework. - -## Files + +## Retrieving Input + +#### Retrieving All Input Data + +You may also retrieve all of the input data as an `array` using the `all` method: + + $input = $request->all(); + +#### Retrieving An Input Value + +Using a few simple methods, you may access all of the user input from your `Illuminate\Http\Request` instance without worrying about which HTTP verb was used for the request. Regardless of the HTTP verb, the `input` method may be used to retrieve user input: + + $name = $request->input('name'); -#### File Upload တစ်ခုကိုပြန်ကြည့်ချင်ရင် - +You may pass a default value as the second argument to the `input` method. This value will be returned if the requested input value is not present on the request: - $file = Input::file('photo'); + $name = $request->input('name', 'Sally'); -#### File upload လုပ်သွားလား မသွားလား ဆုံးဖြတ်ခြင်ရင် +When working with forms that contain array inputs, use "dot" notation to access the arrays: - if (Input::hasFile('photo')) - { - // - } + $name = $request->input('products.0.name'); -The object returned by the `file` method is an instance of the `Symfony\Component\HttpFoundation\File\UploadedFile` class, which extends the PHP `SplFileInfo` class and provides a variety of methods for interacting with the file. + $names = $request->input('products.*.name'); -#### File Upload လုပ်တာမှားလားစစ်ချင်ရင် - +#### Retrieving Input Via Dynamic Properties - if (Input::file('photo')->isValid()) - { - // - } +You may also access user input using dynamic properties on the `Illuminate\Http\Request` instance. For example, if one of your application's forms contains a `name` field, you may access the value of the field like so: -#### Upload File ကို Move လုပ်ချင်ရင် + $name = $request->name; - Input::file('photo')->move($destinationPath); +When using dynamic properties, Laravel will first look for the parameter's value in the request payload. If it is not present, Laravel will search for the field in the route parameters. - Input::file('photo')->move($destinationPath, $fileName); +#### Retrieving JSON Input Values -#### File Upload လုပ်သွားတဲ့ လမ်းကြောင်းရချင်ရင် - +When sending JSON requests to your application, you may access the JSON data via the `input` method as long as the `Content-Type` header of the request is properly set to `application/json`. You may even use "dot" syntax to dig into JSON arrays: - $path = Input::file('photo')->getRealPath(); + $name = $request->input('user.name'); -#### Upload File ရဲ့ မူလအမည်ကိုရချင်ရင် - +#### Retrieving A Portion Of The Input Data - $name = Input::file('photo')->getClientOriginalName(); +If you need to retrieve a subset of the input data, you may use the `only` and `except` methods. Both of these methods accept a single `array` or a dynamic list of arguments: -#### Upload File ရဲ့ extension ကိုသိချင်ရင် + $input = $request->only(['username', 'password']); + + $input = $request->only('username', 'password'); + + $input = $request->except(['credit_card']); + + $input = $request->except('credit_card'); + +#### Determining If An Input Value Is Present + +You should use the `has` method to determine if a value is present on the request. The `has` method returns `true` if the value is present and is not an empty string: + + if ($request->has('name')) { + // + } + + +### Old Input + +Laravel allows you to keep input from one request during the next request. This feature is particularly useful for re-populating forms after detecting validation errors. However, if you are using Laravel's included [validation features](/docs/{{version}}/validation), it is unlikely you will need to manually use these methods, as some of Laravel's built-in validation facilities will call them automatically. + +#### Flashing Input To The Session - $extension = Input::file('photo')->getClientOriginalExtension(); +The `flash` method on the `Illuminate\Http\Request` class will flash the current input to the [session](/docs/{{version}}/session) so that it is available during the user's next request to the application: -#### Upload လုပ်လိုက်တဲ့ File Size ကိုသိချင်ရင် + $request->flash(); - $size = Input::file('photo')->getSize(); +You may also use the `flashOnly` and `flashExcept` methods to flash a subset of the request data to the session. These methods are useful for keeping sensitive information such as passwords out of the session: -#### Upload File ရဲ့ MIME Type ကိုသိချင်ရင် + $request->flashOnly(['username', 'email']); - $mime = Input::file('photo')->getMimeType(); + $request->flashExcept('password'); - -## Request Information +#### Flashing Input Then Redirecting -The `Request` class provides many methods for examining the HTTP request for your application and extends the `Symfony\Component\HttpFoundation\Request` class. Here are some of the highlights. +Since you often will want to flash input to the session and then redirect to the previous page, you may easily chain input flashing onto a redirect using the `withInput` method: -#### Request URI ရဲ့ လမ်းကြောင်းကိုသိချင်ရင် + return redirect('form')->withInput(); - $uri = Request::path(); + return redirect('form')->withInput( + $request->except('password') + ); + +#### Retrieving Old Input + +To retrieve flashed input from the previous request, use the `old` method on the `Request` instance. The `old` method will pull the previously flashed input data from the [session](/docs/{{version}}/session): + + $username = $request->old('username'); + +Laravel also provides a global `old` helper. If you are displaying old input within a [Blade template](/docs/{{version}}/blade), it is more convenient to use the `old` helper. If no old input exists for the given field, `null` will be returned: + + + + +### Cookies + +#### Retrieving Cookies From Requests + +All cookies created by the Laravel framework are encrypted and signed with an authentication code, meaning they will be considered invalid if they have been changed by the client. To retrieve a cookie value from the request, use the `cookie` method on a `Illuminate\Http\Request` instance: + + $value = $request->cookie('name'); + +#### Attaching Cookies To Responses + +You may attach a cookie to an outgoing `Illuminate\Http\Response` instance using the `cookie` method. You should pass the name, value, and number of minutes the cookie should be considered valid to this method: + + return response('Hello World')->cookie( + 'name', 'value', $minutes + ); + +The `cookie` method also accepts a few more arguments which are used less frequently. Generally, these arguments have the same purpose and meaning as the arguments that would be given to PHP's native [setcookie](https://secure.php.net/manual/en/function.setcookie.php) method: + + return response('Hello World')->cookie( + 'name', 'value', $minutes, $path, $domain, $secure, $httpOnly + ); + +#### Generating Cookie Instances + +If you would like to generate a `Symfony\Component\HttpFoundation\Cookie` instance that can be given to a response instance at a later time, you may use the global `cookie` helper. This cookie will not be sent back to the client unless it is attached to a response instance: + + $cookie = cookie('name', 'value', $minutes); + + return response('Hello World')->cookie($cookie); + + +## Files -#### Request Method ကို retrieving လုပ်ချင်ရင် + +### Retrieving Uploaded Files - $method = Request::method(); +You may access uploaded files from a `Illuminate\Http\Request` instance using the `file` method or using dynamic properties. The `file` method returns an instance of the `Illuminate\Http\UploadedFile` class, which extends the PHP `SplFileInfo` class and provides a variety of methods for interacting with the file: - if (Request::isMethod('post')) - { - // - } + $file = $request->file('photo'); -#### Request လမ်းကြောင်းက pattern တစ်ခုနဲ့ mathces ဖြစ်လားဆိုတာကိုဆုံးဖြတ်ချင်ရင် - + $file = $request->photo; - if (Request::is('admin/*')) - { - // - } +You may determine if a file is present on the request using the `hasFile` method: -#### Request URL ကိုရယူခြင်ရင် + if ($request->hasFile('photo')) { + // + } - $url = Request::url(); +#### Validating Successful Uploads -#### Request URI segment ကို retrieve လုပ်ချင်ရင် +In addition to checking if the file is present, you may verify that there were no problems uploading the file via the `isValid` method: - $segment = Request::segment(1); + if ($request->file('photo')->isValid()) { + // + } -#### Request Header ကိုရချင်ရင် - +#### File Paths & Extensions - $value = Request::header('Content-Type'); +The `UploadedFile` class also contains methods for accessing the file's fully-qualified path and its extension. The `extension` method will attempt to guess the file's extension based on its contents. This extension may be different from the extension that was supplied by the client: -#### Retrieving Values From $_SERVER + $path = $request->photo->path(); - $value = Request::server('PATH_INFO'); + $extension = $request->photo->extension(); -#### Request က HTTPS ကလားဆိုတာကိုစစ်ချင်ရင် - +#### Other File Methods - if (Request::secure()) - { - // - } +There are a variety of other methods available on `UploadedFile` instances. Check out the [API documentation for the class](http://api.symfony.com/3.0/Symfony/Component/HttpFoundation/File/UploadedFile.html) for more information regarding these methods. -#### Request က AJAX သုံးထားလားဆိုတာကိုစစ်ချင်ရင် + +### Storing Uploaded Files - if (Request::ajax()) - { - // - } +To store an uploaded file, you will typically use one of your configured [filesystems](/docs/{{version}}/filesystem). The `UploadedFile` class has a `store` method which will move an uploaded file to one of your disks, which may be a location on your local filesystem or even a cloud storage location like Amazon S3. -#### Request မှာ JSON Content Type ရှိလားဆိုတာကိုစစ်ချင်ရင် +The `store` method accepts the path where the file should be stored relative to the filesystem's configured root directory. This path should not contain a file name, since a unique ID will automatically be generated to serve as the file name. - if (Request::isJson()) - { - // - } +The `store` method also accepts an optional second argument for the name of the disk that should be used to store the file. The method will return the path of the file relative to the disk's root: -#### Request က JSON ကို တောင်းလားဆိုတာကိုစစ်ချင်ရင် + $path = $request->photo->store('images'); - if (Request::wantsJson()) - { - // - } + $path = $request->photo->store('images', 's3'); -#### Request ရဲ့ Response ကို Check လုပ်ချင်ရင် +If you do not want a file name to be automatically generated, you may use the `storeAs` method, which accepts the path, file name, and disk name as its arguments: -The `Request::format` method will return the requested response format based on the HTTP Accept header: + $path = $request->photo->storeAs('images', 'filename.jpg'); - if (Request::format() == 'json') - { - // - } + $path = $request->photo->storeAs('images', 'filename.jpg', 's3'); diff --git a/responses.md b/responses.md old mode 100755 new mode 100644 index 5e4ae9d..9acb20c --- a/responses.md +++ b/responses.md @@ -1,228 +1,257 @@ -# Views နှင့် Responses များအကြောင်း +# HTTP Responses -- [Basic Responses](#basic-responses) +- [Creating Responses](#creating-responses) + - [Attaching Headers To Responses](#attaching-headers-to-responses) + - [Attaching Cookies To Responses](#attaching-cookies-to-responses) + - [Cookies & Encryption](#cookies-and-encryption) - [Redirects](#redirects) -- [Views](#views) -- [View Composers](#view-composers) -- [Special Responses](#special-responses) + - [Redirecting To Named Routes](#redirecting-named-routes) + - [Redirecting To Controller Actions](#redirecting-controller-actions) + - [Redirecting With Flashed Session Data](#redirecting-with-flashed-session-data) +- [Other Response Types](#other-response-types) + - [View Responses](#view-responses) + - [JSON Responses](#json-responses) + - [File Downloads](#file-downloads) + - [File Responses](#file-responses) - [Response Macros](#response-macros) - -## Basic Responses + +## Creating Responses -#### String တစ်ခုကို Routes ကနေ return ပြန်ချင်ရင် - +#### Strings & Arrays - Route::get('/', function() - { - return 'Hello World'; - }); +All routes and controllers should return a response to be sent back to the user's browser. Laravel provides several different ways to return responses. The most basic response is simply returning a string from a route or controller. The framework will automatically convert the string into a full HTTP response: -#### Creating Custom Responses - -Symfony\Component\HttpFoundation\Response` class ကနေ Response` တစ်ခုကဖြစ်လာတယ်၊ HTTPS responses တွေကို တည်ဆောက်ဖို့ရာအတွက် များစွာသော methods တွေကနေ စီစဉ်ပေးပါတယ်။ - - $response = Response::make($contents, $statusCode); - - $response->header('Content-Type', $value); - - return $response; - -သင်က `Response` class တစ်ခုရဲ့ method ကိုလည်းလိုချင်တယ်... ဒါပေမယ့် response content အဖြစ် return ပြန်ချင်တယ် ဆိုရင်တော့`Response::view` method ကအဆင်ပြေပါလိမ့်မယ်- - - return Response::view('hello')->header('Content-Type', $type); - -#### Cookies တွေကို Responses တွေဆီပြန်ချင်တယ်ဆိုရင် - - $cookie = Cookie::make('name', 'value'); - - return Response::make($content)->withCookie($cookie); - - -## ပြန်လည်လမ်းကြောင်းညွှန်ကြားမှူ့ + Route::get('/', function () { + return 'Hello World'; + }); -#### Redirect လုပ်ချင်တယ်ဆိုရင် - +In addition to returning strings from your routes and controllers, you may also return arrays. The framework will automatically convert the array into a JSON response: - return Redirect::to('user/login'); + Route::get('/', function () { + return [1, 2, 3]; + }); -#### Flash Data နဲ့ Redirect လုပ်ရင် - +> {tip} Did you know you can also return [Eloquent collections](/docs/{{version}}/eloquent-collections) from your routes or controllers? They will automatically be converted to JSON. Give it a shot! - return Redirect::to('user/login')->with('message', 'Login Failed'); +#### Response Objects -> **Note:** Since the `with` method flashes data to the session, you may retrieve the data using the typical `Session::get` method. +Typically, you won't just be returning simple strings or arrays from your route actions. Instead, you will be returning full `Illuminate\Http\Response` instances or [views](/docs/{{version}}/views). -#### Nmaed Route နှင့် Redirect လုပ်ရင်- +Returning a full `Response` instance allows you to customize the response's HTTP status code and headers. A `Response` instance inherits from the `Symfony\Component\HttpFoundation\Response` class, which provides a variety of methods for building HTTP responses: - return Redirect::route('login'); + Route::get('home', function () { + return response('Hello World', 200) + ->header('Content-Type', 'text/plain'); + }); -#### Route Parameters တစ်ခုနဲ့ Redirect လုပ်ရင် - + +#### Attaching Headers To Responses +Keep in mind that most response methods are chainable, allowing for the fluent construction of response instances. For example, you may use the `header` method to add a series of headers to the response before sending it back to the user: - return Redirect::route('profile', array(1)); + return response($content) + ->header('Content-Type', $type) + ->header('X-Header-One', 'Header Value') + ->header('X-Header-Two', 'Header Value'); -#### Route ထဲမှာ name parameters ပါတာကို Redirect လုပ်ရင် +Or, you may use the `withHeaders` method to specify an array of headers to be added to the response: - return Redirect::route('profile', array('user' => 1)); + return response($content) + ->withHeaders([ + 'Content-Type' => $type, + 'X-Header-One' => 'Header Value', + 'X-Header-Two' => 'Header Value', + ]); -#### Controller ရဲ့ Action တစ်ခုကနေ Redirect တစ်ခု return လုပ်ချင်ရင် + +#### Attaching Cookies To Responses - return Redirect::action('HomeController@index'); +The `cookie` method on response instances allows you to easily attach cookies to the response. For example, you may use the `cookie` method to generate a cookie and fluently attach it to the response instance like so: -#### Paramater ပါတဲ့ Controller တစ်ခုကို Redirect တစ်ခု return လုပ်ခြင်း + return response($content) + ->header('Content-Type', $type) + ->cookie('name', 'value', $minutes); - return Redirect::action('UserController@profile', array(1)); +The `cookie` method also accepts a few more arguments which are used less frequently. Generally, these arguments have the same purpose and meaning as the arguments that would be given to PHP's native [setcookie](https://secure.php.net/manual/en/function.setcookie.php) method: -#### Name Parameters တစ်ခုပါတဲ့ Controller Action တစ်ခုကနေ Redirect တစ်ခု return လုပ်ခြင်း + ->cookie($name, $value, $minutes, $path, $domain, $secure, $httpOnly) - return Redirect::action('UserController@profile', array('user' => 1)); + +#### Cookies & Encryption - -## Views +By default, all cookies generated by Laravel are encrypted and signed so that they can't be modified or read by the client. If you would like to disable encryption for a subset of cookies generated by your application, you may use the `$except` property of the `App\Http\Middleware\EncryptCookies` middleware, which is located in the `app/Http/Middleware` directory: -သင့်ရဲ့ presentation logic ကနေ controller နဲ့ domain logic တွေ ခွဲခြားဖို့ရာအတွက် Views က အဆင်ပြေဆုံးဖြစ်အောင်စီစဉ်ပေးပါတယ်။ -Views Files တွေက `app/views` directory ထဲမှာ ရှိပါတယ်။ Views မှာ ထုံးစံအတိုင်း သင့် application ရဲ့ HTML တွေပါဝင်ပါတယ် ။ + /** + * The names of the cookies that should not be encrypted. + * + * @var array + */ + protected $except = [ + 'cookie_name', + ]; -အောက်မှာဖော်ပြထားတာကတော့ Views နမူနာတစ်ခုပါ: + +## Redirects - +Redirect responses are instances of the `Illuminate\Http\RedirectResponse` class, and contain the proper headers needed to redirect the user to another URL. There are several ways to generate a `RedirectResponse` instance. The simplest method is to use the global `redirect` helper: - - -

    Hello,

    - - + Route::get('dashboard', function () { + return redirect('home/dashboard'); + }); -အဲ့ဒီ့အထက်က View ကို browser ကိုအောက်ကလို retun ပြန်ခဲ့ပါတယ် +Sometimes you may wish to redirect the user to their previous location, such as when a submitted form is invalid. You may do so by using the global `back` helper function. Since this feature utilizes the [session](/docs/{{version}}/session), make sure the route calling the `back` function is using the `web` middleware group or has all of the session middleware applied: - Route::get('/', function() - { - return View::make('greeting', array('name' => 'Taylor')); - }); + Route::post('user/profile', function () { + // Validate the request... -The second argument passed to `View::make` is an array of data that should be made available to the view. + return back()->withInput(); + }); -#### Data တွေကို View ဆီကို pass လုပ်ခြင်း + +### Redirecting To Named Routes - // Using conventional approach - $view = View::make('greeting')->with('name', 'Steve'); +When you call the `redirect` helper with no parameters, an instance of `Illuminate\Routing\Redirector` is returned, allowing you to call any method on the `Redirector` instance. For example, to generate a `RedirectResponse` to a named route, you may use the `route` method: - // Using Magic Methods - $view = View::make('greeting')->withName('steve'); + return redirect()->route('login'); -အထက်ကဥပမာမှာ `$name` variable ကို view ကနေပြီးတော့ access လုပ်နိုင်ပါတယ်၊ နောက် `Steve` ကောပေါ့။ +If your route has parameters, you may pass them as the second argument to the `route` method: -သင့်အနေနဲ့ data ထဲက array တွေကို `make` method ရဲ့ second partameter မှာ array ဖြစ်တဲ့ data ကို pass လုပ်နိုင်ပါတယ်။ သင်လုပ်ချင်ရင်ပေါ့ + // For a route with the following URI: profile/{id} - $view = View::make('greetings', $data); + return redirect()->route('profile', ['id' => 1]); -သင့်အနေနဲ့ data နည်းနည်း လေးကို views အားလုံးကို share နိုင်ပါတယ်၊ +#### Populating Parameters Via Eloquent Models - View::share('name', 'Steve'); +If you are redirecting to a route with an "ID" parameter that is being populated from an Eloquent model, you may simply pass the model itself. The ID will be extracted automatically: -#### View တစ်ခုမှ Sub-View တစ်ခုကို pass လုပ်ခြင်း + // For a route with the following URI: profile/{id} -တစ်ခါတစ်လေသင့်အနေနဲ့ veiw တစ်ခုကနေ တစ်ခုပြောင်းချင်ပါလိမ့်မယ်။ ဥပမာ၊ ဒုတိယ view တစ်ခုကို `app/views/child/view.php` မှာ stored လုပ်ထားတယ်၊ ကျွန်တော်တို့ နောက်ထက် View တစ်ခုကို Pass လုပ်ချင်တယ်ဆိုရင်... like so: + return redirect()->route('profile', [$user]); - $view = View::make('greeting')->nest('child', 'child.view'); +If you would like to customize the value that is placed in the route parameter, you should override the `getRouteKey` method on your Eloquent model: - $view = View::make('greeting')->nest('child', 'child.view', $data); + /** + * Get the value of the model's route key. + * + * @return mixed + */ + public function getRouteKey() + { + return $this->slug; + } -paraent view က sub-view ဆီကနေ render လုပ်နိုင်ပါပြီ- + +### Redirecting To Controller Actions - - -

    Hello!

    - - - +You may also generate redirects to [controller actions](/docs/{{version}}/controllers). To do so, pass the controller and action name to the `action` method. Remember, you do not need to specify the full namespace to the controller since Laravel's `RouteServiceProvider` will automatically set the base controller namespace: - -## View Composers + return redirect()->action('HomeController@index'); -View က rendered ဖြစ်တဲ့အချိန်မှာ View composers တွေက callbacks ဒါမှမဟုတ်ရင် class methods တွေကို ခေါ်ခဲ့တယ် ။ သင့် application မှ render လုပ်ပြီးတော့ သင့်ရဲ့ view ကိုအချိန်တိုင်း သေချာပေါက်ပေးရမယ့် data ရှိတဲ့အခါမျိုးဆိုရင် ... အဲ့ဒီ့ code ကို location တစ်ခုထဲကနေ View Composer တစ်ခုက organize လုပ်နိုင်တယ် ။ +If your controller route requires parameters, you may pass them as the second argument to the `action` method: -#### View Composer တစ်ခု သတ်မှတ်ခြင်း + return redirect()->action( + 'UserController@profile', ['id' => 1] + ); - View::composer('profile', function($view) - { - $view->with('count', User::count()); - }); + +### Redirecting With Flashed Session Data -အခု `profile` view က rendered ဖြစ်တဲ့အချိန်တိုင်းမှာ `count` data က view ဆီကို bound ပါလိမ့်မယ် +Redirecting to a new URL and [flashing data to the session](/docs/{{version}}/session#flash-data) are usually done at the same time. Typically, this is done after successfully performing an action when you flash a success message to the session. For convenience, you may create a `RedirectResponse` instance and flash data to the session in a single, fluent method chain: -View composer တစ်ခုကနေ Multiple Views ကိုတစ်ကြိမ်တည်းသင့်အနေနဲ့ attach လုပ်နိုင်ပါတယ် + Route::post('user/profile', function () { + // Update the user's profile... - View::composer(array('profile','dashboard'), function($view) - { - $view->with('count', User::count()); + return redirect('dashboard')->with('status', 'Profile updated!'); }); -If you would rather use a class based composer, which will provide the benefits of being resolved through the application [IoC Container](ioc.md), you may do so: +After the user is redirected, you may display the flashed message from the [session](/docs/{{version}}/session). For example, using [Blade syntax](/docs/{{version}}/blade): - View::composer('profile', 'ProfileComposer'); + @if (session('status')) +
    + {{ session('status') }} +
    + @endif -View Composer Class တစ်ခုကို အောက်ကလို define လုပ်နိုင်ပါတယ် : + +## Other Response Types - class ProfileComposer { +The `response` helper may be used to generate other types of response instances. When the `response` helper is called without arguments, an implementation of the `Illuminate\Contracts\Routing\ResponseFactory` [contract](/docs/{{version}}/contracts) is returned. This contract provides several helpful methods for generating responses. - public function compose($view) - { - $view->with('count', User::count()); - } + +### View Responses - } +If you need control over the response's status and headers but also need to return a [view](/docs/{{version}}/views) as the response's content, you should use the `view` method: -#### Composer နှစ်ခုသတ်မှတ်ခြင်း + return response() + ->view('hello', $data, 200) + ->header('Content-Type', $type); -တစ်ချိန်တည်းမှာဘဲ Composers Group တွေကို Register လုပ်ဖို့သင့်အနေနဲ့ `composers` method ကိုသုံးနိုင်ပါတယ်။ +Of course, if you do not need to pass a custom HTTP status code or custom headers, you should use the global `view` helper function. + +### JSON Responses - View::composers(array( - 'AdminComposer' => array('admin.index', 'admin.profile'), - 'UserComposer' => 'user', - )); +The `json` method will automatically set the `Content-Type` header to `application/json`, as well as convert the given array to JSON using the `json_encode` PHP function: -> **Note:** There is no convention on where composer classes may be stored. You are free to store them anywhere as long as they can be autoloaded using the directives in your `composer.json` file. + return response()->json([ + 'name' => 'Abigail', + 'state' => 'CA' + ]); -### View Creators ( View ဖန်တီးသူများ) +If you would like to create a JSONP response, you may use the `json` method in combination with the `withCallback` method: -View **creators** တွေက view composers တွေလုပ်သလိုမျိုးတစ်ပုံစံတည်းလုပ်တာပါ။ သို့ပေမယ့်လည်း...view တွေ instantiated ဖြစ်ပြီးပြီဆိုမှ သူတို့က ချက်ချင်း fired လုပ်တာပါ။ View creator တစ်ခုလုပ်ဖို့ Register လုပ်ချင်တယ်ဆိုရင် `creator` method ကိုသုံးပါ။ + return response() + ->json(['name' => 'Abigail', 'state' => 'CA']) + ->withCallback($request->input('callback')); - View::creator('profile', function($view) - { - $view->with('count', User::count()); - }); + +### File Downloads - -## Special Responses +The `download` method may be used to generate a response that forces the user's browser to download the file at the given path. The `download` method accepts a file name as the second argument to the method, which will determine the file name that is seen by the user downloading the file. Finally, you may pass an array of HTTP headers as the third argument to the method: -#### JSON Response တစ်ခုပြုလုပ်ခြင်း + return response()->download($pathToFile); - return Response::json(array('name' => 'Steve', 'state' => 'CA')); + return response()->download($pathToFile, $name, $headers); -#### JSON Response တစ်ခုပြုလုပ်ခြင်း +> {note} Symfony HttpFoundation, which manages file downloads, requires the file being downloaded to have an ASCII file name. - return Response::json(array('name' => 'Steve', 'state' => 'CA'))->setCallback(Input::get('callback')); + +### File Responses -#### File Download Response တစ်ခုပြုလုပ်ခြင်း +The `file` method may be used to display a file, such as an image or PDF, directly in the user's browser instead of initiating a download. This method accepts the path to the file as its first argument and an array of headers as its second argument: - return Response::download($pathToFile); + return response()->file($pathToFile); - return Response::download($pathToFile, $name, $headers); - -> **Note:** Symfony HttpFoundation, which manages file downloads, requires the file being downloaded to have an ASCII file name. + return response()->file($pathToFile, $headers); ## Response Macros -သင့်အနေနဲ့ကိုယ်ပိုင် response တစ်ခုပြုလုပ်ပြီးတော့ routes နဲ့ controllers တွေကနေပြန်ပြီးတော့အသုံးပြုချင်တယ်ဆိုရင်... သင့်အနေနဲ့ `Response::macro` method ကိုသုံးနိုင်ပါတယ် +If you would like to define a custom response that you can re-use in a variety of your routes and controllers, you may use the `macro` method on the `Response` facade. For example, from a [service provider's](/docs/{{version}}/providers) `boot` method: - Response::macro('caps', function($value) - { - return Response::make(strtoupper($value)); - }); + caps('foo'); diff --git a/routing.md b/routing.md old mode 100755 new mode 100644 index 0109ed5..2537788 --- a/routing.md +++ b/routing.md @@ -1,360 +1,312 @@ -# Route လုပ်ခြင်း - -- [လမ်းကြောင်းပေးခြင်း အခြေခံ](#basic-routing) -- [လမ်းကြောင်းထိန်းကွပ် ကိန်းများ](#route-parameters) -- [Route Filterများ](#route-filters) -- [အမည်ရှိ လမ်းကြောင်းများ](#named-routes) -- [လမ်းကြောင်းအုပ်စုများ](#route-groups) -- [Sub-Domain များ အသုံးပြု ၍ လမ်းကြောင်းပေးခြင်း](#sub-domain-routing) -- [လမ်းကြောင်းရှေ့ ဆွယ်ပေးခြင်း](#route-prefixing) -- [လမ်းကြောင်း နှင့် Model ချိတ်တွယ်ခြင်း](#route-model-binding) -- [404 error များ ထုတ်လွှတ်ခြင်း](#throwing-404-errors) -- [Controller များအား လမ်းကြောင်းပေးခြင်း](#routing-to-controllers) +# Routing + +- [Basic Routing](#basic-routing) +- [Route Parameters](#route-parameters) + - [Required Parameters](#required-parameters) + - [Optional Parameters](#parameters-optional-parameters) + - [Regular Expression Constraints](#parameters-regular-expression-constraints) +- [Named Routes](#named-routes) +- [Route Groups](#route-groups) + - [Middleware](#route-group-middleware) + - [Namespaces](#route-group-namespaces) + - [Sub-Domain Routing](#route-group-sub-domain-routing) + - [Route Prefixes](#route-group-prefixes) +- [Route Model Binding](#route-model-binding) + - [Implicit Binding](#implicit-binding) + - [Explicit Binding](#explicit-binding) +- [Form Method Spoofing](#form-method-spoofing) +- [Accessing The Current Route](#accessing-the-current-route) +## Basic Routing -###လမ်းကြောင်းပေးခြင်း(Routing) အခြေခံ +The most basic Laravel routes simply accept a URI and a `Closure`, providing a very simple and expressive method of defining routes: -သင့် application ၏ လမ်းကြောင်း အများစု ကို `app/routes.php` ဖိုင် တွင် သတ်မှတ်ရပါမည်။ `Laravel` တွင် အရိုးရှင်းဆုံး လမ်းကြောင်းတစ်ခုသည် `URI` တစ်ခု နှင့် `closure` ပြန်ခေါ်ချိတ် method (callback method) တစ်ခု ပါ ၀င် ပါသည်။ -#### အခြေခံ GET လမ်းကြောင်း + Route::get('foo', function () { + return 'Hello World'; + }); - Route::get('/', function() - { - return 'Hello World'; - }); +#### The Default Route Files -#### အခြေခံ POST လမ်းကြောင်း +All Laravel routes are defined in your route files, which are located in the `routes` directory. These files are automatically loaded by the framework. The `routes/web.php` file defines routes that are for your web interface. These routes are assigned the `web` middleware group, which provides features like session state and CSRF protection. The routes in `routes/api.php` are stateless and are assigned the `api` middleware group. - Route::post('foo/bar', function() - { - return 'Hello World'; - }); +For most applications, you will begin by defining routes in your `routes/web.php` file. -#### လမ်းကြောင်းတစ်ခုအား HTTP ကြိယာ အများ ဖြင့် မှတ်ပုံတင်ခြင်း +#### Available Router Methods - Route::match(array('GET', 'POST'), '/', function() - { - return 'Hello World'; - }); +The router allows you to register routes that respond to any HTTP verb: -#### လမ်းကြောင်းတစ်ခုအား မည်သည့် HTTP ကြိယာဖြင့် ဖြစ်စေ သက်ဆိုင်စေရန် မှတ်ပုံတင်ခြင်း + Route::get($uri, $callback); + Route::post($uri, $callback); + Route::put($uri, $callback); + Route::patch($uri, $callback); + Route::delete($uri, $callback); + Route::options($uri, $callback); - Route::any('foo', function() - { - return 'Hello World'; - }); +Sometimes you may need to register a route that responds to multiple HTTP verbs. You may do so using the `match` method. Or, you may even register a route that responds to all HTTP verbs using the `any` method: -#### လမ်းကြောင်းတစ်ခုအား HTTPS ဖြင့် မဖြစ်မနေ အသုံးပြ ုစေချင်း + Route::match(['get', 'post'], '/', function () { + // + }); - Route::get('foo', array('https', function() - { - return 'Must be over HTTPS'; - })); + Route::any('foo', function () { + // + }); -မကြာခဏ သင့် လမ်းကြောင်းများအတွက် `URL` များ ထုတ်ရန် လိုအပ်ပါလိမ့်မည်။ ထို့အတွက် `URL::to` method ဖြင့် အသုံးပြုနိုင်ပါသည်။ +#### CSRF Protection - $url = URL::to('foo'); +Any HTML forms pointing to `POST`, `PUT`, or `DELETE` routes that are defined in the `web` routes file should include a CSRF token field. Otherwise, the request will be rejected. You can read more about CSRF protection in the [CSRF documentation](/docs/{{version}}/csrf): - -## လမ်းကြောင်းထိန်းကွပ် ကိန်းရှင်များ - - Route::get('user/{id}', function($id) - { - return 'User '.$id; - }); - -#### မထည့်လည်းရသော လမ်းကြောင်းထိန်းကွပ်ကိန်းရှင်များ - - Route::get('user/{name?}', function($name = null) - { - return $name; - }); - -#### ပေးထားသော မူလတန်ဖိုးများဖြင့် လမ်းကြောင်းထိန်းကွပ်ကိန်းရှင်များ - - Route::get('user/{name?}', function($name = 'John') - { - return $name; - }); - -#### Regular Expression များဖြင့် လမ်းကြောင်းထိန်းကွပ်ကိန်းများအား ကန့်သတ်ခြင်း - - Route::get('user/{name}', function($name) - { - // - }) - ->where('name', '[A-Za-z]+'); - - Route::get('user/{id}', function($id) - { - // - }) - ->where('id', '[0-9]+'); - -#### Where အကန့်အသတ်များအား Array အဖြစ်ဖြင့် ပေးပို့ခြင်း - -အကယ်၍ လို အပ်ပါက ကန့်သတ်ချက်များအား `Array` အဖြစ်တွဲ၍လည်း သုံးနိုင်ပါသည်။ - - Route::get('user/{id}/{name}', function($id, $name) - { - // - }) - ->where(array('id' => '[0-9]+', 'name' => '[a-z]+')) - -#### Global Pattern များ သတ်မှတ်ခြင်း +
    + {{ csrf_field() }} + ... +
    -အကယ်၍ လမ်းကြောင်းထိန်းကွပ်တစ်မျိ ုးအား ပေးထားသော regular expression တစ်ခုဖြင့် ကန့်သတ်လိုပါက `pattern` method ကို အသုံးပြ ုနိုင်ပါသည်။ - - Route::pattern('id', '[0-9]+'); - - Route::get('user/{id}', function($id) - { - // Only called if {id} is numeric. - }); - -#### လမ်းကြောင်းထိန်းကွပ်ကိန်းတစ်ခု၏ တန်ဖိုး ကို အသုံးပြ ုခြင်း - -အကယ်၍ လမ်းကြောင်းထိန်းကွပ် ကိန်းတစ်ခု ၏ တန်ဖိုးအား လမ်းကြောင်း၏ အပြင်ဘက်တွင် အသုံးပြု လိုပါက `Route::input` method ကို အသုံးပြု နိုင်ပါသည်။ - - Route::filter('foo', function() - { - if (Route::input('id') == 1) - { - // - } - }); - - -## Route filter များ + +## Route Parameters -route filter များ သည် ပေးထားသော လမ်းကြောင်းတစ်ခုကို အသုံးပြ ုနိုင်စွမ်း ကန့်သတ်ရာ၌ လွယ်ကူသက်သာအောင် ဖန်တီးပေးထားသော နည်းလမ်းတစ်မျိ ုးဖြစ်ပါသည်။ ၎င်းတို့ သည် သင့် site တွင် အသိအမှတ်ပြု စစ်ဆေးချက်များ (Authentications) လို အပ်ပါက အသုံးဝင်နိုင်ပါသည်။ Laravel framework အတွင်း၌ပင် `auth filter`, `auth.basic filter`, `guest filter`, `csrffilter` အစရှိသဖြင့် များစွာသော route filter များ ပါ၀င်ပါသည်။၎င်းတို့ အားလုံး သည် `app/filters.php` ဖိုင်တွင် တည်ရှိပါသည်။ + +### Required Parameters -#### Route filter တစ်ခု သတ်မှတ်ခြင်း +Of course, sometimes you will need to capture segments of the URI within your route. For example, you may need to capture a user's ID from the URL. You may do so by defining route parameters: - Route::filter('old', function() - { - if (Input::get('age') < 200) - { - return Redirect::to('home'); - } - }); + Route::get('user/{id}', function ($id) { + return 'User '.$id; + }); -အကယ်၍ ပေးထားသော Web Server ၏ တုန့်ပြန်ချက် သည် route filter တစ်ခုဆီမှ ပြန်လာခြင်းဖြစ်ပါက ထို တုန့်ပြန်ချက်အား မူလတောင်းဆိုချက်၏ တုန့်ပြန်ချက်အဖြစ် စဉ်းစားမည်ဖြစ်ပြီး လမ်းကြောင်းကို execute လုပ်မည် မဟုတ်ပါ။ထို့ပြင် သတ်မှတ်ထားပြီးသော နောက်ဆွယ် route filters(after filters)ကို လည်း ပျက်ပြယ်စေမည် ဖြစ်ပါသည်။ +You may define as many route parameters as required by your route: -#### လမး်ကြောင်းတစ်ခုပေါ်သို့ Route filter တစ်ခု ချိတ်ဆက်ခြင်း + Route::get('posts/{post}/comments/{comment}', function ($postId, $commentId) { + // + }); - Route::get('user', array('before' => 'old', function() - { - return 'You are over 200 years old!'; - })); +Route parameters are always encased within `{}` braces and should consist of alphabetic characters. Route parameters may not contain a `-` character. Use an underscore (`_`) instead. -#### Controller Action တစ်ခု သို့ Route filter တစ်ခု ချိတ်ဆက်ခြင်း + +### Optional Parameters - Route::get('user', array('before' => 'old', 'uses' => 'UserController@showProfile')); +Occasionally you may need to specify a route parameter, but make the presence of that route parameter optional. You may do so by placing a `?` mark after the parameter name. Make sure to give the route's corresponding variable a default value: -#### လမ်းကြောင်းတစ်ခုပေါ်သို့ Route filter အများ ချိတ်ဆက်ခြင်း + Route::get('user/{name?}', function ($name = null) { + return $name; + }); - Route::get('user', array('before' => 'auth|old', function() - { - return 'You are authenticated and over 200 years old!'; - })); + Route::get('user/{name?}', function ($name = 'John') { + return $name; + }); -#### လမ်းကြောင်းတစ်ခုပေါ်သို့ Route filter အများ အား Array အဖြစ်ဖြင့် ချိတ်ဆက်ခြင်း + +### Regular Expression Constraints - Route::get('user', array('before' => array('auth', 'old'), function() - { - return 'You are authenticated and over 200 years old!'; - })); +You may constrain the format of your route parameters using the `where` method on a route instance. The `where` method accepts the name of the parameter and a regular expression defining how the parameter should be constrained: -#### Route filter ထိန်းကွပ်ကိန်းများ သတ်မှတ်ခြင်း + Route::get('user/{name}', function ($name) { + // + })->where('name', '[A-Za-z]+'); - Route::filter('age', function($route, $request, $value) - { - // - }); + Route::get('user/{id}', function ($id) { + // + })->where('id', '[0-9]+'); - Route::get('user', array('before' => 'age:200', function() - { - return 'Hello World'; - })); + Route::get('user/{id}/{name}', function ($id, $name) { + // + })->where(['id' => '[0-9]+', 'name' => '[a-z]+']); -နောက်ဆွယ် Route filter များ သည် `$response` အား တတိယမြောက် argument အဖြစ် လက်ခံရရှိပါသည်။ + +#### Global Constraints - Route::filter('log', function($route, $request, $response) - { - // - }); +If you would like a route parameter to always be constrained by a given regular expression, you may use the `pattern` method. You should define these patterns in the `boot` method of your `RouteServiceProvider`: -#### Pattern အခြေခံ Filter များ + /** + * Define your route model bindings, pattern filters, etc. + * + * @return void + */ + public function boot() + { + Route::pattern('id', '[0-9]+'); -Route filter တစ်ခုအား လမ်းကြောင်းတို့၏ URI ပေါ် အခြေခံ ၍ သတ်မှတ်ထားသော လမ်းကြောင်း အုပ်စုတစ်ခု လုံး ပေါ်သို့ သက်ရောက်စေရန်လည်း သတ်မှတ်နိုင်ပါသည်။ + parent::boot(); + } - Route::filter('admin', function() - { - // - }); +Once the pattern has been defined, it is automatically applied to all routes using that parameter name: - Route::when('admin/*', 'admin'); + Route::get('user/{id}', function ($id) { + // Only executed if {id} is numeric... + }); -ပေးထားသော ဥပမာတွင် `admin` route filter သည် `admin/` ဖြင့် စသော လမ်းကြောင်းအားလုံး ပေါ်သို့ သက်ရောက်မည် ဖြစ်ပါသည်။ ခရေပွင့် စာလုံး `*` ကို မည်သည့် စာလုံးနှင့်မဆို ကိုက်ညီစေမည့် သံခိတ် စာလုံး အဖြစ် အသုံးပြု နိုင်ပါသည်။ + +## Named Routes -ထို့ အပြင် HTTP ကြိယာများဖြင့်လည်း pattern အခြေခံ filter များ အား ကန့်သတ်နိုင်ပါသည်။ -You may also constrain pattern filters by HTTP verbs: +Named routes allow the convenient generation of URLs or redirects for specific routes. You may specify a name for a route by chaining the `name` method onto the route definition: - Route::when('admin/*', 'admin', array('post')); + Route::get('user/profile', function () { + // + })->name('profile'); -#### Filter class များ +You may also specify route names for controller actions: -အဆင့်မြင့် route filter များ တွင် Closure တစ်ခု ထက် class တစ်ခုကို အသုံးပြု ချင် ကောင်း အသုံးပြု ပါလိမ့်မည်။စင်စစ် filter class များသည် application [IoC Container](ioc.md) မှ တစ်ဆင့် ပြန်ဖြည်ချင်းဖြစ်ရာ dependency injection ကို အသုံး ပြု နိုင်စေ၍ test လုပ်ခြင်းကို အထောက်အပံ့ကောင်းကောင်းပေးနိုင်ပါသည်။ + Route::get('user/profile', 'UserController@showProfile')->name('profile'); -#### Class အခြေခံ filter တစ်ခု အား မှတ်ပုံတင်ခြင်း +#### Generating URLs To Named Routes - Route::filter('foo', 'FooFilter'); +Once you have assigned a name to a given route, you may use the route's name when generating URLs or redirects via the global `route` function: -ပုံမှန်အားဖြင့် `FooFilter` class ၏ `filter` method ကို ခေါ်ပါလိမ့်မည်။ + // Generating URLs... + $url = route('profile'); - class FooFilter { + // Generating Redirects... + return redirect()->route('profile'); - public function filter() - { - // Filter logic... - } +If the named route defines parameters, you may pass the parameters as the second argument to the `route` function. The given parameters will automatically be inserted into the URL in their correct positions: - } + Route::get('user/{id}/profile', function ($id) { + // + })->name('profile'); -အကယ်၍ `filter` method ကို မသုံးလိုပါက အခြား method တစ်ခုကို သတ်မှတ်လိုက်ရုံပင်။ + $url = route('profile', ['id' => 1]); - Route::filter('foo', 'FooFilter@foo'); + +## Route Groups - -## အမည်ရှိ လမ်းကြောင်းများ +Route groups allow you to share route attributes, such as middleware or namespaces, across a large number of routes without needing to define those attributes on each individual route. Shared attributes are specified in an array format as the first parameter to the `Route::group` method. -အမည်ရှိလမ်းကြောင်းများသည် လမ်းကြောင်းလွှဲများ ပြု လုပ်သောအခါ သို့မဟုတ် URL များ ရေးသားသောအခါ လမ်းကြောင်းများကို ညွှန်းဆိုရာ ၌ ပိုမိုလွယ်ကူစေပါသည်။ + +### Middleware - Route::get('user/profile', array('as' => 'profile', function() - { - // - })); +To assign middleware to all routes within a group, you may use the `middleware` key in the group attribute array. Middleware are executed in the order they are listed in the array: -Controller action အတွဲများ အတွက် လည်း လမ်းကြောင်းအမည်များ သတ်မှတ်နိုင်ပါသည်။ + Route::group(['middleware' => 'auth'], function () { + Route::get('/', function () { + // Uses Auth Middleware + }); - Route::get('user/profile', array('as' => 'profile', 'uses' => 'UserController@showProfile')); + Route::get('user/profile', function () { + // Uses Auth Middleware + }); + }); -အထက်ပါအတိုင်းသတ်မှတ်ပြီးပါက ပေးထားသော လမ်းကြောင်းနာမည်ဖြင့် URL များ ထုတ်ရာ၌ ဖြစ်စေ လမ်းကြောင်းလွှဲများ အသုံးပြု ရာ ၌ ဖြစ်စေ သုံးနိုင်ပါပြီ။ + +### Namespaces - $url = URL::route('profile'); +Another common use-case for route groups is assigning the same PHP namespace to a group of controllers using the `namespace` parameter in the group array: - $redirect = Redirect::route('profile'); + Route::group(['namespace' => 'Admin'], function () { + // Controllers Within The "App\Http\Controllers\Admin" Namespace + }); -လက်ရှိ ရောက်ရှိနေသော လမ်းကြောင်း၏ အမည်ကို `currentRouteName` method ဖြင့် သိရှိအသုံးပြု နိုင်ပါသည်။ +Remember, by default, the `RouteServiceProvider` includes your route files within a namespace group, allowing you to register controller routes without specifying the full `App\Http\Controllers` namespace prefix. So, you only need to specify the portion of the namespace that comes after the base `App\Http\Controllers` namespace. - $name = Route::currentRouteName(); + +### Sub-Domain Routing - -## လမ်းကြောင်း အုပ်စုများ +Route groups may also be used to handle sub-domain routing. Sub-domains may be assigned route parameters just like route URIs, allowing you to capture a portion of the sub-domain for usage in your route or controller. The sub-domain may be specified using the `domain` key on the group attribute array: -တစ်ခါတစ်ရံ လမ်းကြောင်း အုပ်စု တစ်ခု ပေါ်သို့ filter များ သက်ရောက်ဖို့ လိုအပ်ကောင်းလိုအပ်နိုင်ပါသည်။ ထိုအခါမျိ ုးတွင် လမ်းကြောင်းတစ်ခုစီအတွက် filter များသတ်မှတ်မည့်အစား လမ်းကြောင်းအုပ်စု တစ်ခုကို အသုံးပြု နိုင်ပါသည်။ + Route::group(['domain' => '{account}.myapp.com'], function () { + Route::get('user/{id}', function ($account, $id) { + // + }); + }); - Route::group(array('before' => 'auth'), function() - { - Route::get('/', function() - { - // Has Auth Filter - }); + +### Route Prefixes - Route::get('user/profile', function() - { - // Has Auth Filter - }); - }); +The `prefix` group attribute may be used to prefix each route in the group with a given URI. For example, you may want to prefix all route URIs within the group with `admin`: -`group` array အတွင်းတွင်`namespace` ထိန်းကွပ်ကိန်းထည့်၍ လည်း ပေးထားသော အုပ်စုအတွင်းရှိ controller များအား namespace တစ်ခုအတွင်း ကျရောက်နေစေရန် စီမံနိုင်ပါသည်။ + Route::group(['prefix' => 'admin'], function () { + Route::get('users', function () { + // Matches The "/admin/users" URL + }); + }); - Route::group(array('namespace' => 'Admin'), function() - { - // - }); + +## Route Model Binding - -## Sub-Domain များ အသုံးပြု ၍ လမ်းကြောင်းပေးခြင်း +When injecting a model ID to a route or controller action, you will often query to retrieve the model that corresponds to that ID. Laravel route model binding provides a convenient way to automatically inject the model instances directly into your routes. For example, instead of injecting a user's ID, you can inject the entire `User` model instance that matches the given ID. -Laravel လမ်းကြောင်းများတွင် သံခိတ်သုံး sub-domain များကို ကောင်းမွန်စွာ စီမံအသုံးချနိုင်ပြီး domain မှ သံခိတ် ထိန်းကွပ်ကိန်းများ ကို ပေးပို့နိုင်ပါသည်။ + +### Implicit Binding -#### Sub-domain လမ်းကြောင်းများ မှတ်ပုံတင်ခြင်း +Laravel automatically resolves Eloquent models defined in routes or controller actions whose variable names match a route segment name. For example: - Route::group(array('domain' => '{account}.myapp.com'), function() - { + Route::get('api/users/{user}', function (App\User $user) { + return $user->email; + }); - Route::get('user/{id}', function($account, $id) - { - // - }); +In this example, since the Eloquent `$user` variable defined on the route matches the `{user}` segment in the route's URI, Laravel will automatically inject the model instance that has an ID matching the corresponding value from the request URI. If a matching model instance is not found in the database, a 404 HTTP response will automatically be generated. - }); +#### Customizing The Key Name - -## လမ်းကြောင်းရှေ့ ဆွယ်ပေးခြင်း +If you would like model binding to use a database column other than `id` when retrieving a given model class, you may override the `getRouteKeyName` method on the Eloquent model: -လမ်းကြောင်း အုပ်စု တစ်ခု အား `prefix` ထိန်းကွပ်ကိန်းအား `group` array တွင် ထည့်သွင်း၍ ရှေ့ ဆွယ် လမ်းကြောင်းတစ်ခုပေးနိုင်ပါသည်။ + /** + * Get the route key for the model. + * + * @return string + */ + public function getRouteKeyName() + { + return 'slug'; + } - Route::group(array('prefix' => 'admin'), function() - { + +### Explicit Binding - Route::get('user', function() - { - // - }); +To register an explicit binding, use the router's `model` method to specify the class for a given parameter. You should define your explicit model bindings in the `boot` method of the `RouteServiceProvider` class: - }); + public function boot() + { + parent::boot(); - -## လမ်းကြောင်း နှင့် Model ချိတ်တွယ်ခြင်း + Route::model('user', App\User::class); + } -Model ချိတ်တွယ်ခြင်း သည် model instance တစ်ခုအား လမ်းကြောင်းများ အတွင်းသို့ အလွယ်တကူ ထိုးသွင်းနိုင်စေပါသည်။ ဥပမာ user တစ်ယောက်၏ id ကို လမ်းကြောင်းအတွင်း ထည့်သွင်းမည့်အစား ပေးထားသော id နှင့် ကိုက်ညီသည့် user model instance တစ်ခုကို တိုက်ရိုက်ထည့်သွင်းနိုင်ပါသည်။ ပထမဦးစွာ`Route::model` method ကို အသုံးပြု ပြီး ပေးထားသော ထိန်းကွပ်ကိန်းအတွင်း အသုံးပြု မည့် model အမည်ကို သတ်မှတ်ပေးရပါမည်။ +Next, define a route that contains a `{user}` parameter: -#### ထိန်းကွပ်ကိန်းတစ်ခုအား model တစ်ခုဖြင့် ချိတ်တွယ်ခြင်း + Route::get('profile/{user}', function (App\User $user) { + // + }); - Route::model('user', 'User'); +Since we have bound all `{user}` parameters to the `App\User` model, a `User` instance will be injected into the route. So, for example, a request to `profile/1` will inject the `User` instance from the database which has an ID of `1`. -ပြီးနောက် `{user}` ထိန်းကွပ်ကိန်းပါ၀င်သည့် လမ်းကြောင်းတစ်ခု သတ်မှတ်ပေးရပါမည်။ +If a matching model instance is not found in the database, a 404 HTTP response will be automatically generated. - Route::get('profile/{user}', function(User $user) - { - // - }); +#### Customizing The Resolution Logic -`{user}` ထိန်းကွပ်ကိန်းကို `User` model ဖြင့် ချိတ်တွယ်ခဲ့သဖြင့် `User` instance တစ်ခုကို လမ်းကြောင်းအတွင်းသို့ ထိုးသွင်းပါလိမ့်မည်။ ဥပမာအားဖြင့် `profile/1` သို့ လာသော တောင်းဆိုချက်တစ်ခုသည် ID 1 ရှိသော `User` instance တစ်ခုကို ထိုးသွင်းပါလိမ့်မည်။ +If you wish to use your own resolution logic, you may use the `Route::bind` method. The `Closure` you pass to the `bind` method will receive the value of the URI segment and should return the instance of the class that should be injected into the route: ->**မှတ်ချက်** အကယ်၍ ကိုက်ညီသည့် model instance တစ်ခုကို database တွင် ရှာမတွေ့ ပါက 404 error ဖြစ်ပေါ်ပါလိမ့်မည်။ + public function boot() + { + parent::boot(); -အကယ်၍ မိမိဘာသာ "not found" တုန့်ပြန်ချက်တစ်ခု သတ်မှတ်လိုပါက `model` method တွင် Closure တစ်ခုအား တတိယ arugment အဖြစ် ပေးပို့နိုင်ပါသည်။ + Route::bind('user', function ($value) { + return App\User::where('name', $value)->first(); + }); + } - Route::model('user', 'User', function() - { - throw new NotFoundHttpException; - }); + +## Form Method Spoofing -တစ်ခါတစ်ရံ ကိုယ်တိုင် လမ်းကြောင်းထိန်းကွပ်ကိန်းများ မိမိ ဘာသာ ဖြည်လိုခြင်း မျိ ုးရှိနိုင်ပါသည်။ ထို့ အတွက် `Route::bind` method ကို သုံးလိုက်ရုံပင်။ +HTML forms do not support `PUT`, `PATCH` or `DELETE` actions. So, when defining `PUT`, `PATCH` or `DELETE` routes that are called from an HTML form, you will need to add a hidden `_method` field to the form. The value sent with the `_method` field will be used as the HTTP request method: - Route::bind('user', function($value, $route) - { - return User::where('name', $value)->first(); - }); +
    + + +
    - -## 404 error များ ထုတ်လွှတ်ခြင်း +You may use the `method_field` helper to generate the `_method` input: -လမ်းကြောင်းတစ်ခု ဆီမှ 404 error တစ်ခု ဖြစ်ပေါ်အောင် ကိုယ်တိုင် ပြု လုပ်နည်း နှစ်မျ ိုး ရှိပါသည်။ ပထမတစ်နည်း မှာ `App::abort` method ကို အသုံးပြု ခြင်းဖြစ်သည်။ + {{ method_field('PUT') }} - App::abort(404); + +## Accessing The Current Route -ဒုတိယတည်နည်းမှာ `Symfony\Component\HttpKernel\Exception\NotFoundHttpException` ကို ကိုယ်တိုင် ထုတ်လွှတ်ခြင်းဖြစ်သည်။ +You may use the `current`, `currentRouteName`, and `currentRouteAction` methods on the `Route` facade to access information about the route handling the incoming request: -404 exception များ ကိုင်တွယ်ခြင်း နှင့် ၎င်းတို့ အတွက် ကိုယ်ပိုင်တုန့်ပြန်ချက်များ ပြု လုပ်ခြင်းတို့ နှင့် ပတ်သက်၍ [errors](errors#handling-404-errors.md) အပိုင်းတွင် ပိုမို ဖတ်ရှုနိုင်ပါသည်။ + $route = Route::current(); - -## Controller များ အား လမ်းကြောင်းပေးခြင်း + $name = Route::currentRouteName(); -Laravel တွင် လမ်းကြောင်းပေးရာ၌ Closure များ ကိုသာ မဟုတ် controller class များကို လည်း အသုံးပြု နိုင်သည့် အပြင် [resource controllers](/docs/controllers#resource-controllers လမ်းကြောင်းများ ပါ ခွင့်ပြုထားပါသည်။ + $action = Route::currentRouteAction(); -[Controllers](controllers.md) လမ်းညွှန် တွင်အသေးစိတ် ဖတ်ရှု နိုင်ပါသည်။ +Refer to the API documentation for both the [underlying class of the Route facade](https://laravel.com/api/{{version}}/Illuminate/Routing/Router.html) and [Route instance](https://laravel.com/api/{{version}}/Illuminate/Routing/Route.html) to review all accessible methods. diff --git a/scheduling.md b/scheduling.md new file mode 100644 index 0000000..f280078 --- /dev/null +++ b/scheduling.md @@ -0,0 +1,222 @@ +# Task Scheduling + +- [Introduction](#introduction) +- [Defining Schedules](#defining-schedules) + - [Schedule Frequency Options](#schedule-frequency-options) + - [Preventing Task Overlaps](#preventing-task-overlaps) + - [Maintenance Mode](#maintenance-mode) +- [Task Output](#task-output) +- [Task Hooks](#task-hooks) + + +## Introduction + +In the past, you may have generated a Cron entry for each task you needed to schedule on your server. However, this can quickly become a pain, because your task schedule is no longer in source control and you must SSH into your server to add additional Cron entries. + +Laravel's command scheduler allows you to fluently and expressively define your command schedule within Laravel itself. When using the scheduler, only a single Cron entry is needed on your server. Your task schedule is defined in the `app/Console/Kernel.php` file's `schedule` method. To help you get started, a simple example is defined within the method. + +### Starting The Scheduler + +When using the scheduler, you only need to add the following Cron entry to your server. If you do not know how to add Cron entries to your server, consider using a service such as [Laravel Forge](https://forge.laravel.com) which can manage the Cron entries for you: + + * * * * * php /path/to/artisan schedule:run >> /dev/null 2>&1 + +This Cron will call the Laravel command scheduler every minute. When the `schedule:run` command is executed, Laravel will evaluate your scheduled tasks and runs the tasks that are due. + + +## Defining Schedules + +You may define all of your scheduled tasks in the `schedule` method of the `App\Console\Kernel` class. To get started, let's look at an example of scheduling a task. In this example, we will schedule a `Closure` to be called every day at midnight. Within the `Closure` we will execute a database query to clear a table: + + call(function () { + DB::table('recent_users')->delete(); + })->daily(); + } + } + +In addition to scheduling `Closure` calls, you may also schedule [Artisan commands](/docs/{{version}}/artisan) and operating system commands. For example, you may use the `command` method to schedule an Artisan command using either the command's name or class: + + $schedule->command('emails:send --force')->daily(); + + $schedule->command(EmailsCommand::class, ['--force'])->daily(); + +The `exec` command may be used to issue a command to the operating system: + + $schedule->exec('node /home/forge/script.js')->daily(); + + +### Schedule Frequency Options + +Of course, there are a variety of schedules you may assign to your task: + +Method | Description +------------- | ------------- +`->cron('* * * * * *');` | Run the task on a custom Cron schedule +`->everyMinute();` | Run the task every minute +`->everyFiveMinutes();` | Run the task every five minutes +`->everyTenMinutes();` | Run the task every ten minutes +`->everyThirtyMinutes();` | Run the task every thirty minutes +`->hourly();` | Run the task every hour +`->hourlyAt(17);` | Run the task every hour at 17 mins past the hour +`->daily();` | Run the task every day at midnight +`->dailyAt('13:00');` | Run the task every day at 13:00 +`->twiceDaily(1, 13);` | Run the task daily at 1:00 & 13:00 +`->weekly();` | Run the task every week +`->monthly();` | Run the task every month +`->monthlyOn(4, '15:00');` | Run the task every month on the 4th at 15:00 +`->quarterly();` | Run the task every quarter +`->yearly();` | Run the task every year +`->timezone('America/New_York');` | Set the timezone + +These methods may be combined with additional constraints to create even more finely tuned schedules that only run on certain days of the week. For example, to schedule a command to run weekly on Monday: + + // Run once per week on Monday at 1 PM... + $schedule->call(function () { + // + })->weekly()->mondays()->at('13:00'); + + // Run hourly from 8 AM to 5 PM on weekdays... + $schedule->command('foo') + ->weekdays() + ->hourly() + ->timezone('America/Chicago') + ->between('8:00', '17:00'); + +Below is a list of the additional schedule constraints: + +Method | Description +------------- | ------------- +`->weekdays();` | Limit the task to weekdays +`->sundays();` | Limit the task to Sunday +`->mondays();` | Limit the task to Monday +`->tuesdays();` | Limit the task to Tuesday +`->wednesdays();` | Limit the task to Wednesday +`->thursdays();` | Limit the task to Thursday +`->fridays();` | Limit the task to Friday +`->saturdays();` | Limit the task to Saturday +`->between($start, $end);` | Limit the task to run between start and end times +`->when(Closure);` | Limit the task based on a truth test + +#### Between Time Constraints + +The `between` method may be used to limit the execution of a task based on the time of day: + + $schedule->command('reminders:send') + ->hourly() + ->between('7:00', '22:00'); + +Similarly, the `unlessBetween` method can be used to exclude the execution of a task for a period of time: + + $schedule->command('reminders:send') + ->hourly() + ->unlessBetween('23:00', '4:00'); + +#### Truth Test Constraints + +The `when` method may be used to limit the execution of a task based on the result of a given truth test. In other words, if the given `Closure` returns `true`, the task will execute as long as no other constraining conditions prevent the task from running: + + $schedule->command('emails:send')->daily()->when(function () { + return true; + }); + +The `skip` method may be seen as the inverse of `when`. If the `skip` method returns `true`, the scheduled task will not be executed: + + $schedule->command('emails:send')->daily()->skip(function () { + return true; + }); + +When using chained `when` methods, the scheduled command will only execute if all `when` conditions return `true`. + + +### Preventing Task Overlaps + +By default, scheduled tasks will be run even if the previous instance of the task is still running. To prevent this, you may use the `withoutOverlapping` method: + + $schedule->command('emails:send')->withoutOverlapping(); + +In this example, the `emails:send` [Artisan command](/docs/{{version}}/artisan) will be run every minute if it is not already running. The `withoutOverlapping` method is especially useful if you have tasks that vary drastically in their execution time, preventing you from predicting exactly how long a given task will take. + + +### Maintenance Mode + +Laravel's scheduled tasks will not run when Laravel is in [maintenance mode](/docs/{{version}}/configuration#maintenance-mode), since we don't want your tasks to interfere with any unfinished maintenance you may be performing on your server. However, if you would like to force a task to run even in maintenance mode, you may use the `evenInMaintenanceMode` method: + + $schedule->command('emails:send')->evenInMaintenanceMode(); + + +## Task Output + +The Laravel scheduler provides several convenient methods for working with the output generated by scheduled tasks. First, using the `sendOutputTo` method, you may send the output to a file for later inspection: + + $schedule->command('emails:send') + ->daily() + ->sendOutputTo($filePath); + +If you would like to append the output to a given file, you may use the `appendOutputTo` method: + + $schedule->command('emails:send') + ->daily() + ->appendOutputTo($filePath); + +Using the `emailOutputTo` method, you may e-mail the output to an e-mail address of your choice. Before e-mailing the output of a task, you should configure Laravel's [e-mail services](/docs/{{version}}/mail): + + $schedule->command('foo') + ->daily() + ->sendOutputTo($filePath) + ->emailOutputTo('foo@example.com'); + +> {note} The `emailOutputTo`, `sendOutputTo` and `appendOutputTo` methods are exclusive to the `command` method and are not supported for `call`. + + +## Task Hooks + +Using the `before` and `after` methods, you may specify code to be executed before and after the scheduled task is complete: + + $schedule->command('emails:send') + ->daily() + ->before(function () { + // Task is about to start... + }) + ->after(function () { + // Task is complete... + }); + +#### Pinging URLs + +Using the `pingBefore` and `thenPing` methods, the scheduler can automatically ping a given URL before or after a task is complete. This method is useful for notifying an external service, such as [Laravel Envoyer](https://envoyer.io), that your scheduled task is commencing or has finished execution: + + $schedule->command('emails:send') + ->daily() + ->pingBefore($url) + ->thenPing($url); + +Using either the `pingBefore($url)` or `thenPing($url)` feature requires the Guzzle HTTP library. You can add Guzzle to your project using the Composer package manager: + + composer require guzzlehttp/guzzle diff --git a/schema.md b/schema.md deleted file mode 100755 index 4b2b6fb..0000000 --- a/schema.md +++ /dev/null @@ -1,216 +0,0 @@ -# Schema Builder - -- [Introduction](#introduction) -- [Creating & Dropping Tables](#creating-and-dropping-tables) -- [Adding Columns](#adding-columns) -- [Renaming Columns](#renaming-columns) -- [Dropping Columns](#dropping-columns) -- [Checking Existence](#checking-existence) -- [Adding Indexes](#adding-indexes) -- [Foreign Keys](#foreign-keys) -- [Dropping Indexes](#dropping-indexes) -- [Dropping Timestamps & Soft Deletes](#dropping-timestamps) -- [Storage Engines](#storage-engines) - - -## Introduction - -The Laravel `Schema` class provides a database agnostic way of manipulating tables. It works well with all of the databases supported by Laravel, and has a unified API across all of these systems. - - -## Creating & Dropping Tables - -To create a new database table, the `Schema::create` method is used: - - Schema::create('users', function($table) - { - $table->increments('id'); - }); - -The first argument passed to the `create` method is the name of the table, and the second is a `Closure` which will receive a `Blueprint` object which may be used to define the new table. - -To rename an existing database table, the `rename` method may be used: - - Schema::rename($from, $to); - -To specify which connection the schema operation should take place on, use the `Schema::connection` method: - - Schema::connection('foo')->create('users', function($table) - { - $table->increments('id'); - }); - -To drop a table, you may use the `Schema::drop` method: - - Schema::drop('users'); - - Schema::dropIfExists('users'); - - -## Adding Columns - -To update an existing table, we will use the `Schema::table` method: - - Schema::table('users', function($table) - { - $table->string('email'); - }); - -The table builder contains a variety of column types that you may use when building your tables: - -Command | Description -------------- | ------------- -`$table->bigIncrements('id');` | Incrementing ID using a "big integer" equivalent. -`$table->bigInteger('votes');` | BIGINT equivalent to the table -`$table->binary('data');` | BLOB equivalent to the table -`$table->boolean('confirmed');` | BOOLEAN equivalent to the table -`$table->char('name', 4);` | CHAR equivalent with a length -`$table->date('created_at');` | DATE equivalent to the table -`$table->dateTime('created_at');` | DATETIME equivalent to the table -`$table->decimal('amount', 5, 2);` | DECIMAL equivalent with a precision and scale -`$table->double('column', 15, 8);` | DOUBLE equivalent with precision -`$table->enum('choices', array('foo', 'bar'));` | ENUM equivalent to the table -`$table->float('amount');` | FLOAT equivalent to the table -`$table->increments('id');` | Incrementing ID to the table (primary key). -`$table->integer('votes');` | INTEGER equivalent to the table -`$table->longText('description');` | LONGTEXT equivalent to the table -`$table->mediumInteger('numbers');` | MEDIUMINT equivalent to the table -`$table->mediumText('description');` | MEDIUMTEXT equivalent to the table -`$table->morphs('taggable');` | Adds INTEGER `taggable_id` and STRING `taggable_type` -`$table->nullableTimestamps();` | Same as `timestamps()`, except allows NULLs -`$table->smallInteger('votes');` | SMALLINT equivalent to the table -`$table->tinyInteger('numbers');` | TINYINT equivalent to the table -`$table->softDeletes();` | Adds **deleted\_at** column for soft deletes -`$table->string('email');` | VARCHAR equivalent column -`$table->string('name', 100);` | VARCHAR equivalent with a length -`$table->text('description');` | TEXT equivalent to the table -`$table->time('sunrise');` | TIME equivalent to the table -`$table->timestamp('added_on');` | TIMESTAMP equivalent to the table -`$table->timestamps();` | Adds **created\_at** and **updated\_at** columns -`->nullable()` | Designate that the column allows NULL values -`->default($value)` | Declare a default value for a column -`->unsigned()` | Set INTEGER to UNSIGNED - -#### Using After On MySQL - -If you are using the MySQL database, you may use the `after` method to specify the order of columns: - - $table->string('name')->after('email'); - - -## Renaming Columns - -To rename a column, you may use the `renameColumn` method on the Schema builder. Before renaming a column, be sure to add the `doctrine/dbal` dependency to your `composer.json` file. - - Schema::table('users', function($table) - { - $table->renameColumn('from', 'to'); - }); - -> **Note:** Renaming `enum` column types is not supported. - - -## Dropping Columns - -#### Dropping A Column From A Database Table - - Schema::table('users', function($table) - { - $table->dropColumn('votes'); - }); - -#### Dropping Multiple Columns From A Database Table - - Schema::table('users', function($table) - { - $table->dropColumn('votes', 'avatar', 'location'); - }); - - -## Checking Existence - -#### Checking For Existence Of Table - -You may easily check for the existence of a table or column using the `hasTable` and `hasColumn` methods: - - if (Schema::hasTable('users')) - { - // - } - -#### Checking For Existence Of Columns - - if (Schema::hasColumn('users', 'email')) - { - // - } - - -## Adding Indexes - -The schema builder supports several types of indexes. There are two ways to add them. First, you may fluently define them on a column definition, or you may add them separately: - - $table->string('email')->unique(); - -Or, you may choose to add the indexes on separate lines. Below is a list of all available index types: - -Command | Description -------------- | ------------- -`$table->primary('id');` | Adding a primary key -`$table->primary(array('first', 'last'));` | Adding composite keys -`$table->unique('email');` | Adding a unique index -`$table->index('state');` | Adding a basic index - - -## Foreign Keys - -Laravel also provides support for adding foreign key constraints to your tables: - - $table->foreign('user_id')->references('id')->on('users'); - -In this example, we are stating that the `user_id` column references the `id` column on the `users` table. - -You may also specify options for the "on delete" and "on update" actions of the constraint: - - $table->foreign('user_id') - ->references('id')->on('users') - ->onDelete('cascade'); - -To drop a foreign key, you may use the `dropForeign` method. A similar naming convention is used for foreign keys as is used for other indexes: - - $table->dropForeign('posts_user_id_foreign'); - -> **Note:** When creating a foreign key that references an incrementing integer, remember to always make the foreign key column `unsigned`. - - -## Dropping Indexes - -To drop an index you must specify the index's name. Laravel assigns a reasonable name to the indexes by default. Simply concatenate the table name, the names of the column in the index, and the index type. Here are some examples: - -Command | Description -------------- | ------------- -`$table->dropPrimary('users_id_primary');` | Dropping a primary key from the "users" table -`$table->dropUnique('users_email_unique');` | Dropping a unique index from the "users" table -`$table->dropIndex('geo_state_index');` | Dropping a basic index from the "geo" table - - -## Dropping Timestamps & SoftDeletes - -To drop the `timestamps`, `nullableTimestamps` or `softDeletes` column types, you may use the following methods: - -Command | Description -------------- | ------------- -`$table->dropTimestamps();` | Dropping the **created\_at** and **updated\_at** columns from the table -`$table->dropSoftDeletes();` | Dropping **deleted\_at** column from the table - - -## Storage Engines - -To set the storage engine for a table, set the `engine` property on the schema builder: - - Schema::create('users', function($table) - { - $table->engine = 'InnoDB'; - - $table->string('email'); - }); diff --git a/scout.md b/scout.md new file mode 100644 index 0000000..915a1ed --- /dev/null +++ b/scout.md @@ -0,0 +1,303 @@ +# Laravel Scout + +- [Introduction](#introduction) +- [Installation](#installation) + - [Queueing](#queueing) + - [Driver Prerequisites](#driver-prerequisites) +- [Configuration](#configuration) + - [Configuring Model Indexes](#configuring-model-indexes) + - [Configuring Searchable Data](#configuring-searchable-data) +- [Indexing](#indexing) + - [Batch Import](#batch-import) + - [Adding Records](#adding-records) + - [Updating Records](#updating-records) + - [Removing Records](#removing-records) + - [Pausing Indexing](#pausing-indexing) +- [Searching](#searching) + - [Where Clauses](#where-clauses) + - [Pagination](#pagination) +- [Custom Engines](#custom-engines) + + +## Introduction + +Laravel Scout provides a simple, driver based solution for adding full-text search to your [Eloquent models](/docs/{{version}}/eloquent). Using model observers, Scout will automatically keep your search indexes in sync with your Eloquent records. + +Currently, Scout ships with an [Algolia](https://www.algolia.com/) driver; however, writing custom drivers is simple and you are free to extend Scout with your own search implementations. + + +## Installation + +First, install the Scout via the Composer package manager: + + composer require laravel/scout + +Next, you should add the `ScoutServiceProvider` to the `providers` array of your `config/app.php` configuration file: + + Laravel\Scout\ScoutServiceProvider::class, + +After registering the Scout service provider, you should publish the Scout configuration using the `vendor:publish` Artisan command. This command will publish the `scout.php` configuration file to your `config` directory: + + php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider" + +Finally, add the `Laravel\Scout\Searchable` trait to the model you would like to make searchable. This trait will register a model observer to keep the model in sync with your search driver: + + +### Queueing + +While not strictly required to use Scout, you should strongly consider configuring a [queue driver](/docs/{{version}}/queues) before using the library. Running a queue worker will allow Scout to queue all operations that sync your model information to your search indexes, providing much better response times for your application's web interface. + +Once you have configured a queue driver, set the value of the `queue` option in your `config/scout.php` configuration file to `true`: + + 'queue' => true, + + +### Driver Prerequisites + +#### Algolia + +When using the Algolia driver, you should configure your Algolia `id` and `secret` credentials in your `config/scout.php` configuration file. Once your credentials have been configured, you will also need to install the Algolia PHP SDK via the Composer package manager: + + composer require algolia/algoliasearch-client-php + + +## Configuration + + +### Configuring Model Indexes + +Each Eloquent model is synced with a given search "index", which contains all of the searchable records for that model. In other words, you can think of each index like a MySQL table. By default, each model will be persisted to an index matching the model's typical "table" name. Typically, this is the plural form of the model name; however, you are free to customize the model's index by overriding the `searchableAs` method on the model: + + +### Configuring Searchable Data + +By default, the entire `toArray` form of a given model will be persisted to its search index. If you would like to customize the data that is synchronized to the search index, you may override the `toSearchableArray` method on the model: + + toArray(); + + // Customize array... + + return $array; + } + } + + +## Indexing + + +### Batch Import + +If you are installing Scout into an existing project, you may already have database records you need to import into your search driver. Scout provides an `import` Artisan command that you may use to import all of your existing records into your search indexes: + + php artisan scout:import "App\Post" + + +### Adding Records + +Once you have added the `Laravel\Scout\Searchable` trait to a model, all you need to do is `save` a model instance and it will automatically be added to your search index. If you have configured Scout to [use queues](#queueing) this operation will be performed in the background by your queue worker: + + $order = new App\Order; + + // ... + + $order->save(); + +#### Adding Via Query + +If you would like to add a collection of models to your search index via an Eloquent query, you may chain the `searchable` method onto an Eloquent query. The `searchable` method will [chunk the results](/docs/{{version}}/eloquent#chunking-results) of the query and add the records to your search index. Again, if you have configured Scout to use queues, all of the chunks will be added in the background by your queue workers: + + // Adding via Eloquent query... + App\Order::where('price', '>', 100)->searchable(); + + // You may also add records via relationships... + $user->orders()->searchable(); + + // You may also add records via collections... + $orders->searchable(); + +The `searchable` method can be considered an "upsert" operation. In other words, if the model record is already in your index, it will be updated. If it does not exist in the search index, it will be added to the index. + + +### Updating Records + +To update a searchable model, you only need to update the model instance's properties and `save` the model to your database. Scout will automatically persist the changes to your search index: + + $order = App\Order::find(1); + + // Update the order... + + $order->save(); + +You may also use the `searchable` method on an Eloquent query to update a collection of models. If the models do not exist in your search index, they will be created: + + // Updating via Eloquent query... + App\Order::where('price', '>', 100)->searchable(); + + // You may also update via relationships... + $user->orders()->searchable(); + + // You may also update via collections... + $orders->searchable(); + + +### Removing Records + +To remove a record from your index, simply `delete` the model from the database. This form of removal is even compatible with [soft deleted](/docs/{{version}}/eloquent#soft-deleting) models: + + $order = App\Order::find(1); + + $order->delete(); + +If you do not want to retrieve the model before deleting the record, you may use the `unsearchable` method on an Eloquent query instance or collection: + + // Removing via Eloquent query... + App\Order::where('price', '>', 100)->unsearchable(); + + // You may also remove via relationships... + $user->orders()->unsearchable(); + + // You may also remove via collections... + $orders->unsearchable(); + + +### Pausing Indexing + +Sometimes you may need to perform a batch of Eloquent operations on a model without syncing the model data to your search index. You may do this using the `withoutSyncingToSearch` method. This method accepts a single callback which will be immediately executed. Any model operations that occur within the callback will not be synced to the model's index: + + App\Order::withoutSyncingToSearch(function () { + // Perform model actions... + }); + + +## Searching + +You may begin searching a model using the `search` method. The search method accepts a single string that will be used to search your models. You should then chain the `get` method onto the search query to retrieve the Eloquent models that match the given search query: + + $orders = App\Order::search('Star Trek')->get(); + +Since Scout searches return a collection of Eloquent models, you may even return the results directly from a route or controller and they will automatically be converted to JSON: + + use Illuminate\Http\Request; + + Route::get('/search', function (Request $request) { + return App\Order::search($request->search)->get(); + }); + + +### Where Clauses + +Scout allows you to add simple "where" clauses to your search queries. Currently, these clauses only support basic numeric equality checks, and are primarily useful for scoping search queries by a tenant ID. Since a search index is not a relational database, more advanced "where" clauses are not currently supported: + + $orders = App\Order::search('Star Trek')->where('user_id', 1)->get(); + + +### Pagination + +In addition to retrieving a collection of models, you may paginate your search results using the `paginate` method. This method will return a `Paginator` instance just as if you had [paginated a traditional Eloquent query](/docs/{{version}}/pagination): + + $orders = App\Order::search('Star Trek')->paginate(); + +You may specify how many models to retrieve per page by passing the amount as the first argument to the `paginate` method: + + $orders = App\Order::search('Star Trek')->paginate(15); + +Once you have retrieved the results, you may display the results and render the page links using [Blade](/docs/{{version}}/blade) just as if you had paginated a traditional Eloquent query: + +
    + @foreach ($orders as $order) + {{ $order->price }} + @endforeach +
    + + {{ $orders->links() }} + + +## Custom Engines + +#### Writing The Engine + +If one of the built-in Scout search engines doesn't fit your needs, you may write your own custom engine and register it with Scout. Your engine should extend the `Laravel\Scout\Engines\Engine` abstract class. This abstract class contains five methods your custom engine must implement: + + use Laravel\Scout\Builder; + + abstract public function update($models); + abstract public function delete($models); + abstract public function search(Builder $builder); + abstract public function paginate(Builder $builder, $perPage, $page); + abstract public function map($results, $model); + +You may find it helpful to review the implementations of these methods on the `Laravel\Scout\Engines\AlgoliaEngine` class. This class will provide you with a good starting point for learning how to implement each of these methods in your own engine. + +#### Registering The Engine + +Once you have written your custom engine, you may register it with Scout using the `extend` method of the Scout engine manager. You should call the `extend` method from the `boot` method of your `AppServiceProvider` or any other service provider used by your application. For example, if you have written a `MySqlSearchEngine`, you may register it like so: + + use Laravel\Scout\EngineManager; + + /** + * Bootstrap any application services. + * + * @return void + */ + public function boot() + { + resolve(EngineManager::class)->extend('mysql', function () { + return new MySqlSearchEngine; + }); + } + +Once your engine has been registered, you may specify it as your default Scout `driver` in your `config/scout.php` configuration file: + + 'driver' => 'mysql', diff --git a/security.md b/security.md deleted file mode 100755 index 01e7c15..0000000 --- a/security.md +++ /dev/null @@ -1,310 +0,0 @@ -# Security - -- [Configuration](#configuration) -- [Storing Passwords](#storing-passwords) -- [Authenticating Users](#authenticating-users) -- [Manually Logging In Users](#manually) -- [Protecting Routes](#protecting-routes) -- [HTTP Basic Authentication](#http-basic-authentication) -- [Password Reminders & Reset](#password-reminders-and-reset) -- [Encryption](#encryption) -- [Authentication Drivers](#authentication-drivers) - - -## Configuration - -Laravel aims to make implementing authentication very simple. In fact, almost everything is configured for you out of the box. The authentication configuration file is located at `app/config/auth.php`, which contains several well documented options for tweaking the behavior of the authentication facilities. - -By default, Laravel includes a `User` model in your `app/models` directory which may be used with the default Eloquent authentication driver. Please remember when building the Schema for this Model to ensure that the password field is a minimum of 60 characters. - -If your application is not using Eloquent, you may use the `database` authentication driver which uses the Laravel query builder. - -> **Note:** Before getting started, make sure that your `users` (or equivalent) table contains a nullable, string `remember_token` column of 100 characters. This column will be used to store a token for "remember me" sessions being maintained by your application. - - -## Storing Passwords - -The Laravel `Hash` class provides secure Bcrypt hashing: - -#### Hashing A Password Using Bcrypt - - $password = Hash::make('secret'); - -#### Verifying A Password Against A Hash - - if (Hash::check('secret', $hashedPassword)) - { - // The passwords match... - } - -#### Checking If A Password Needs To Be Rehashed - - if (Hash::needsRehash($hashed)) - { - $hashed = Hash::make('secret'); - } - - -## Authenticating Users - -To log a user into your application, you may use the `Auth::attempt` method. - - if (Auth::attempt(array('email' => $email, 'password' => $password))) - { - return Redirect::intended('dashboard'); - } - -Take note that `email` is not a required option, it is merely used for example. You should use whatever column name corresponds to a "username" in your database. The `Redirect::intended` function will redirect the user to the URL they were trying to access before being caught by the authentication filter. A fallback URI may be given to this method in case the intended destination is not available. - -When the `attempt` method is called, the `auth.attempt` [event](events.md) will be fired. If the authentication attempt is successful and the user is logged in, the `auth.login` event will be fired as well. - -#### Determining If A User Is Authenticated - -To determine if the user is already logged into your application, you may use the `check` method: - - if (Auth::check()) - { - // The user is logged in... - } - -#### Authenticating A User And "Remembering" Them - -If you would like to provide "remember me" functionality in your application, you may pass `true` as the second argument to the `attempt` method, which will keep the user authenticated indefinitely (or until they manually logout). Of course, your `users` table must include the string `remember_token` column, which will be used to store the "remember me" token. - - if (Auth::attempt(array('email' => $email, 'password' => $password), true)) - { - // The user is being remembered... - } - -**Note:** If the `attempt` method returns `true`, the user is considered logged into the application. - -#### Determining If User Authed Via Remember -If you are "remembering" user logins, you may use the `viaRemember` method to determine if the user was authenticated using the "remember me" cookie: - - if (Auth::viaRemember()) - { - // - } - -#### Authenticating A User With Conditions - -You also may add extra conditions to the authenticating query: - - if (Auth::attempt(array('email' => $email, 'password' => $password, 'active' => 1))) - { - // The user is active, not suspended, and exists. - } - -> **Note:** For added protection against session fixation, the user's session ID will automatically be regenerated after authenticating. - -#### Accessing The Logged In User - -Once a user is authenticated, you may access the User model / record: - - $email = Auth::user()->email; - -To retrieve the authenticated user's ID, you may use the `id` method: - - $id = Auth::id(); - -To simply log a user into the application by their ID, use the `loginUsingId` method: - - Auth::loginUsingId(1); - -#### Validating User Credentials Without Login - -The `validate` method allows you to validate a user's credentials without actually logging them into the application: - - if (Auth::validate($credentials)) - { - // - } - -#### Logging A User In For A Single Request - -You may also use the `once` method to log a user into the application for a single request. No sessions or cookies will be utilized. - - if (Auth::once($credentials)) - { - // - } - -#### Logging A User Out Of The Application - - Auth::logout(); - - -## Manually Logging In Users - -If you need to log an existing user instance into your application, you may simply call the `login` method with the instance: - - $user = User::find(1); - - Auth::login($user); - -This is equivalent to logging in a user via credentials using the `attempt` method. - - -## Protecting Routes - -Route filters may be used to allow only authenticated users to access a given route. Laravel provides the `auth` filter by default, and it is defined in `app/filters.php`. - -#### Protecting A Route - - Route::get('profile', array('before' => 'auth', function() - { - // Only authenticated users may enter... - })); - -### CSRF Protection - -Laravel provides an easy method of protecting your application from cross-site request forgeries. - -#### Inserting CSRF Token Into Form - - - -#### Validate The Submitted CSRF Token - - Route::post('register', array('before' => 'csrf', function() - { - return 'You gave a valid CSRF token!'; - })); - - -## HTTP Basic Authentication - -HTTP Basic Authentication provides a quick way to authenticate users of your application without setting up a dedicated "login" page. To get started, attach the `auth.basic` filter to your route: - -#### Protecting A Route With HTTP Basic - - Route::get('profile', array('before' => 'auth.basic', function() - { - // Only authenticated users may enter... - })); - -By default, the `basic` filter will use the `email` column on the user record when authenticating. If you wish to use another column you may pass the column name as the first parameter to the `basic` method in your `app/filters.php` file: - - Route::filter('auth.basic', function() - { - return Auth::basic('username'); - }); - -#### Setting Up A Stateless HTTP Basic Filter - -You may also use HTTP Basic Authentication without setting a user identifier cookie in the session, which is particularly useful for API authentication. To do so, define a filter that returns the `onceBasic` method: - - Route::filter('basic.once', function() - { - return Auth::onceBasic(); - }); - -If you are using PHP FastCGI, HTTP Basic authentication will not work correctly by default. The following lines should be added to your `.htaccess` file: - - RewriteCond %{HTTP:Authorization} ^(.+)$ - RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] - - -## Password Reminders & Reset - -### Model & Table - -Most web applications provide a way for users to reset their forgotten passwords. Rather than forcing you to re-implement this on each application, Laravel provides convenient methods for sending password reminders and performing password resets. To get started, verify that your `User` model implements the `Illuminate\Auth\Reminders\RemindableInterface` contract. Of course, the `User` model included with the framework already implements this interface, and uses the `Illuminate\Auth\Reminders\RemindableTrait` to include the methods needed to implement the interface. - -#### Implementing The RemindableInterface - - use Illuminate\Auth\Reminders\RemindableTrait; - use Illuminate\Auth\Reminders\RemindableInterface; - - class User extends Eloquent implements RemindableInterface { - - use RemindableTrait; - - } - -#### Generating The Reminder Table Migration - -Next, a table must be created to store the password reset tokens. To generate a migration for this table, simply execute the `auth:reminders-table` Artisan command: - - php artisan auth:reminders-table - - php artisan migrate - -### Password Reminder Controller - -Now we're ready to generate the password reminder controller. To automatically generate a controller, you may use the `auth:reminders-controller` Artisan command, which will create a `RemindersController.php` file in your `app/controllers` directory. - - php artisan auth:reminders-controller - -The generated controller will already have a `getRemind` method that handles showing your password reminder form. All you need to do is create a `password.remind` [view](responses#views.md). This view should have a basic form with an `email` field. The form should POST to the `RemindersController@postRemind` action. - -A simple form on the `password.remind` view might look like this: - -
    - - -
    - -In addition to `getRemind`, the generated controller will already have a `postRemind` method that handles sending the password reminder e-mails to your users. This method expects the `email` field to be present in the `POST` variables. If the reminder e-mail is successfully sent to the user, a `status` message will be flashed to the session. If the reminder fails, an `error` message will be flashed instead. - -Within the `postRemind` controller method you may modify the message instance before it is sent to the user: - - Password::remind(Input::only('email'), function($message) - { - $message->subject('Password Reminder'); - }); - -Your user will receive an e-mail with a link that points to the `getReset` method of the controller. The password reminder token, which is used to identify a given password reminder attempt, will also be passed to the controller method. The action is already configured to return a `password.reset` view which you should build. The `token` will be passed to the view, and you should place this token in a hidden form field named `token`. In addition to the `token`, your password reset form should contain `email`, `password`, and `password_confirmation` fields. The form should POST to the `RemindersController@postReset` method. - -A simple form on the `password.reset` view might look like this: - -
    - - - - - -
    - -Finally, the `postReset` method is responsible for actually changing the password in storage. In this controller action, the Closure passed to the `Password::reset` method sets the `password` attribute on the `User` and calls the `save` method. Of course, this Closure is assuming your `User` model is an [Eloquent model](eloquent.md); however, you are free to change this Closure as needed to be compatible with your application's database storage system. - -If the password is successfully reset, the user will be redirected to the root of your application. Again, you are free to change this redirect URL. If the password reset fails, the user will be redirect back to the reset form, and an `error` message will be flashed to the session. - -### Password Validation - -By default, the `Password::reset` method will verify that the passwords match and are >= six characters. You may customize these rules using the `Password::validator` method, which accepts a Closure. Within this Closure, you may do any password validation you wish. Note that you are not required to verify that the passwords match, as this will be done automatically by the framework. - - Password::validator(function($credentials) - { - return strlen($credentials['password']) >= 6; - }); - -> **Note:** By default, password reset tokens expire after one hour. You may change this via the `reminder.expire` option of your `app/config/auth.php` file. - - -## Encryption - -Laravel provides facilities for strong AES encryption via the mcrypt PHP extension: - -#### Encrypting A Value - - $encrypted = Crypt::encrypt('secret'); - -> **Note:** Be sure to set a 16, 24, or 32 character random string in the `key` option of the `app/config/app.php` file. Otherwise, encrypted values will not be secure. - -#### Decrypting A Value - - $decrypted = Crypt::decrypt($encryptedValue); - -#### Setting The Cipher & Mode - -You may also set the cipher and mode used by the encrypter: - - Crypt::setMode('ctr'); - - Crypt::setCipher($cipher); - - -## Authentication Drivers - -Laravel offers the `database` and `eloquent` authentication drivers out of the box. For more information about adding additional authentication drivers, check out the [Authentication extension documentation](extending#authentication.md). diff --git a/seeding.md b/seeding.md new file mode 100644 index 0000000..ddd9ed4 --- /dev/null +++ b/seeding.md @@ -0,0 +1,94 @@ +# Database: Seeding + +- [Introduction](#introduction) +- [Writing Seeders](#writing-seeders) + - [Using Model Factories](#using-model-factories) + - [Calling Additional Seeders](#calling-additional-seeders) +- [Running Seeders](#running-seeders) + + +## Introduction + +Laravel includes a simple method of seeding your database with test data using seed classes. All seed classes are stored in the `database/seeds` directory. Seed classes may have any name you wish, but probably should follow some sensible convention, such as `UsersTableSeeder`, etc. By default, a `DatabaseSeeder` class is defined for you. From this class, you may use the `call` method to run other seed classes, allowing you to control the seeding order. + + +## Writing Seeders + +To generate a seeder, execute the `make:seeder` [Artisan command](/docs/{{version}}/artisan). All seeders generated by the framework will be placed in the `database/seeds` directory: + + php artisan make:seeder UsersTableSeeder + +A seeder class only contains one method by default: `run`. This method is called when the `db:seed` [Artisan command](/docs/{{version}}/artisan) is executed. Within the `run` method, you may insert data into your database however you wish. You may use the [query builder](/docs/{{version}}/queries) to manually insert data or you may use [Eloquent model factories](/docs/{{version}}/database-testing#writing-factories). + +As an example, let's modify the default `DatabaseSeeder` class and add a database insert statement to the `run` method: + + insert([ + 'name' => str_random(10), + 'email' => str_random(10).'@gmail.com', + 'password' => bcrypt('secret'), + ]); + } + } + + +### Using Model Factories + +Of course, manually specifying the attributes for each model seed is cumbersome. Instead, you can use [model factories](/docs/{{version}}/database-testing#writing-factories) to conveniently generate large amounts of database records. First, review the [model factory documentation](/docs/{{version}}/database-testing#writing-factories) to learn how to define your factories. Once you have defined your factories, you may use the `factory` helper function to insert records into your database. + +For example, let's create 50 users and attach a relationship to each user: + + /** + * Run the database seeds. + * + * @return void + */ + public function run() + { + factory(App\User::class, 50)->create()->each(function ($u) { + $u->posts()->save(factory(App\Post::class)->make()); + }); + } + + +### Calling Additional Seeders + +Within the `DatabaseSeeder` class, you may use the `call` method to execute additional seed classes. Using the `call` method allows you to break up your database seeding into multiple files so that no single seeder class becomes overwhelmingly large. Simply pass the name of the seeder class you wish to run: + + /** + * Run the database seeds. + * + * @return void + */ + public function run() + { + $this->call(UsersTableSeeder::class); + $this->call(PostsTableSeeder::class); + $this->call(CommentsTableSeeder::class); + } + + +## Running Seeders + +Once you have written your seeder classes, you may use the `db:seed` Artisan command to seed your database. By default, the `db:seed` command runs the `DatabaseSeeder` class, which may be used to call other seed classes. However, you may use the `--class` option to specify a specific seeder class to run individually: + + php artisan db:seed + + php artisan db:seed --class=UsersTableSeeder + +You may also seed your database using the `migrate:refresh` command, which will also rollback and re-run all of your migrations. This command is useful for completely re-building your database: + + php artisan migrate:refresh --seed diff --git a/session.md b/session.md old mode 100755 new mode 100644 index 3fd4c83..346c2d7 --- a/session.md +++ b/session.md @@ -1,121 +1,269 @@ -# ဆက်ရှင် - -- [ပြင်ဆင်ခြင်း](#configuration) -- [Session Usage](#session-usage) -- [Flash Data](#flash-data) -- [Database Sessions](#database-sessions) -- [Session Drivers](#session-drivers) +# HTTP Session + +- [Introduction](#introduction) + - [Configuration](#configuration) + - [Driver Prerequisites](#driver-prerequisites) +- [Using The Session](#using-the-session) + - [Retrieving Data](#retrieving-data) + - [Storing Data](#storing-data) + - [Flash Data](#flash-data) + - [Deleting Data](#deleting-data) + - [Regenerating The Session ID](#regenerating-the-session-id) +- [Adding Custom Session Drivers](#adding-custom-session-drivers) + - [Implementing The Driver](#implementing-the-driver) + - [Registering The Driver](#registering-the-driver) + + +## Introduction + +Since HTTP driven applications are stateless, sessions provide a way to store information about the user across multiple requests. Laravel ships with a variety of session backends that are accessed through an expressive, unified API. Support for popular backends such as [Memcached](https://memcached.org), [Redis](http://redis.io), and databases is included out of the box. -## ပြင်ဆင်ခြင်း +### Configuration + +The session configuration file is stored at `config/session.php`. Be sure to review the options available to you in this file. By default, Laravel is configured to use the `file` session driver, which will work well for many applications. In production applications, you may consider using the `memcached` or `redis` drivers for even faster session performance. + +The session `driver` configuration option defines where session data will be stored for each request. Laravel ships with several great drivers out of the box: + +
    +- `file` - sessions are stored in `storage/framework/sessions`. +- `cookie` - sessions are stored in secure, encrypted cookies. +- `database` - sessions are stored in a relational database. +- `memcached` / `redis` - sessions are stored in one of these fast, cache based stores. +- `array` - sessions are stored in a PHP array and will not be persisted. +
    + +> {tip} The array driver is used during [testing](/docs/{{version}}/testing) and prevents the data stored in the session from being persisted. + + +### Driver Prerequisites + +#### Database + +When using the `database` session driver, you will need to create a table to contain the session items. Below is an example `Schema` declaration for the table: + + Schema::create('sessions', function ($table) { + $table->string('id')->unique(); + $table->integer('user_id')->nullable(); + $table->string('ip_address', 45)->nullable(); + $table->text('user_agent')->nullable(); + $table->text('payload'); + $table->integer('last_activity'); + }); + +You may use the `session:table` Artisan command to generate this migration: + + php artisan session:table + + php artisan migrate + +#### Redis + +Before using Redis sessions with Laravel, you will need to install the `predis/predis` package (~1.0) via Composer. You may configure your Redis connections in the `database` configuration file. In the `session` configuration file, the `connection` option may be used to specify which Redis connection is used by the session. + + +## Using The Session + + +### Retrieving Data -HTTP မှာ Stateless protocol ဖြစ်သောကြောင့် request တစ်ခုနှင့်တစ်ခု ကြားထဲတွင် Session ထဲတွင် အချက်အလက်များကို သိမ်းဆည်းကာ ပို ့ဆောင်ရပေသည်။ Laravel တွင် session ကို နည်းလမ်းမျိုးစုံဖြင့် အသုံးပြုနိုင်ရန် API တစ်ခုကို ဖန်တီးကာ စုစည်းထားသည်။ အခြားသော ကျော်ကြားသည့် -[Memcached](http://memcached.org) နှင့် [Redis](http://redis.io), Session အဖြစ်အသုံးပြုနိုင်သည့် နည်းလမ်းများကို ပံ့ပိုးထားသည်။ +There are two primary ways of working with session data in Laravel: the global `session` helper and via a `Request` instance. First, let's look at accessing the session via a `Request` instance, which can be type-hinted on a controller method. Remember, controller method dependencies are automatically injected via the Laravel [service container](/docs/{{version}}/container): -Session နှင့်ပတ်သတ်သည့် အချက်အလက်များကို `app/config/session.php` တွင် လိုအပ်သလို ပြောင်းလဲ ရမည် ဖြစ်သည်။ ပုံမှန်အားဖြင့် application အတော်များများတွင် အဆင်ပြေမည့် `file` session driver ကို အသုံးပြုထားသည်။ + session()->get('key'); - -## Session Usage + // + } + } -#### Storing An Item In The Session +When you retrieve a value from the session, you may also pass a default value as the second argument to the `get` method. This default value will be returned if the specified key does not exist in the session. If you pass a `Closure` as the default value to the `get` method and the requested key does not exist, the `Closure` will be executed and its result returned: - Session::put('key', 'value'); + $value = $request->session()->get('key', 'default'); -#### Push A Value Onto An Array Session Value + $value = $request->session()->get('key', function () { + return 'default'; + }); - Session::push('user.teams', 'developers'); +#### The Global Session Helper -#### Retrieving An Item From The Session +You may also use the global `session` PHP function to retrieve and store data in the session. When the `session` helper is called with a single, string argument, it will return the value of that session key. When the helper is called with an array of key / value pairs, those values will be stored in the session: - $value = Session::get('key'); + Route::get('home', function () { + // Retrieve a piece of data from the session... + $value = session('key'); -#### Retrieving An Item Or Returning A Default Value + // Specifying a default value... + $value = session('key', 'default'); - $value = Session::get('key', 'default'); + // Store a piece of data in the session... + session(['key' => 'value']); + }); - $value = Session::get('key', function() { return 'default'; }); +> {tip} There is little practical difference between using the session via an HTTP request instance versus using the global `session` helper. Both methods are [testable](/docs/{{version}}/testing) via the `assertSessionHas` method which is available in all of your test cases. -#### Session မှ value တစ်ခု ထုတ်ယူကာ ဖယ်ထုတ်ခြင်း +#### Retrieving All Session Data - $value = Session::pull('key', 'default'); +If you would like to retrieve all the data in the session, you may use the `all` method: -#### Session မှ value များအားလုံး ခေါ်ယူခြင်း + $data = $request->session()->all(); - $data = Session::all(); +#### Determining If An Item Exists In The Session -#### Session မှ item ရှိမရှိ စစ်ဆေးခြင်း +To determine if a value is present in the session, you may use the `has` method. The `has` method returns `true` if the value is present and is not `null`: - if (Session::has('users')) - { - // - } + if ($request->session()->has('users')) { + // + } -#### Session မှ item တစ်ခုကို ထုတ်ပယ်ခြင်း +To determine if a value is present in the session, even if its value is `null`, you may use the `exists` method. The `exists` method returns `true` if the value is present: - Session::forget('key'); + if ($request->session()->exists('users')) { + // + } -#### Session တစ်ခုလုံး ရှင်းပစ်ခြင်း + +### Storing Data - Session::flush(); +To store data in the session, you will typically use the `put` method or the `session` helper: -#### Session ID အသစ်ထုတ်ယူခြင်း + // Via a request instance... + $request->session()->put('key', 'value'); - Session::regenerate(); + // Via the global helper... + session(['key' => 'value']); + +#### Pushing To Array Session Values + +The `push` method may be used to push a new value onto a session value that is an array. For example, if the `user.teams` key contains an array of team names, you may push a new value onto the array like so: + + $request->session()->push('user.teams', 'developers'); + +#### Retrieving & Deleting An Item + +The `pull` method will retrieve and delete an item from the session in a single statement: + + $value = $request->session()->pull('key', 'default'); -## Flash Data +### Flash Data + +Sometimes you may wish to store items in the session only for the next request. You may do so using the `flash` method. Data stored in the session using this method will only be available during the subsequent HTTP request, and then will be deleted. Flash data is primarily useful for short-lived status messages: + + $request->session()->flash('status', 'Task was successful!'); + +If you need to keep your flash data around for several requests, you may use the `reflash` method, which will keep all of the flash data for an additional request. If you only need to keep specific flash data, you may use the `keep` method: + + $request->session()->reflash(); + + $request->session()->keep(['username', 'email']); + + +### Deleting Data + +The `forget` method will remove a piece of data from the session. If you would like to remove all data from the session, you may use the `flush` method: + + $request->session()->forget('key'); + + $request->session()->flush(); -တခါတရံ တစ်ချို ့သော data များကို နောက်ထပ် request တစ်ခါစာသာ သိမ်းဆည်းလိုပေမည်။ ထိုသို ့ပြုလုပ်နိုင်ရန် `Session::flash` method ကို အသုံးပြုနိုင်သည်။ + +### Regenerating The Session ID - Session::flash('key', 'value'); +Regenerating the session ID is often done in order to prevent malicious users from exploiting a [session fixation](https://en.wikipedia.org/wiki/Session_fixation) attack on your application. -#### နောက်ထပ် request တစ်ခုစာ သက်တမ်းတိုးခြင်း +Laravel automatically regenerates the session ID during authentication if you are using the built-in `LoginController`; however, if you need to manually regenerate the session ID, you may use the `regenerate` method. - Session::reflash(); + $request->session()->regenerate(); -#### နောက်ထပ် request တစ်ခုစာ သက်တမ်းတိုးခြင်း (ရွေးချယ်ထားသော data များသာ) + +## Adding Custom Session Drivers - Session::keep(array('username', 'email')); + +#### Implementing The Driver - -## Database Sessions +Your custom session driver should implement the `SessionHandlerInterface`. This interface contains just a few simple methods we need to implement. A stubbed MongoDB implementation looks something like this: + string('id')->unique(); - $table->text('payload'); - $table->integer('last_activity'); - }); + class MongoHandler implements SessionHandlerInterface + { + public function open($savePath, $sessionName) {} + public function close() {} + public function read($sessionId) {} + public function write($sessionId, $data) {} + public function destroy($sessionId) {} + public function gc($lifetime) {} + } - -Table ကို အသုံးပြုထားသောကြောင့် `session:table` ဟူသည့် Artisan command ကို အသုံးပြုပြီး migration ပြုလုပ်နိုင်သည်။ +> {tip} Laravel does not ship with a directory to contain your extensions. You are free to place them anywhere you like. In this example, we have created an `Extensions` directory to house the `MongoHandler`. +Since the purpose of these methods is not readily understandable, let's quickly cover what each of the methods do: - php artisan session:table +
    +- The `open` method would typically be used in file based session store systems. Since Laravel ships with a `file` session driver, you will almost never need to put anything in this method. You can leave it as an empty stub. It is simply a fact of poor interface design (which we'll discuss later) that PHP requires us to implement this method. +- The `close` method, like the `open` method, can also usually be disregarded. For most drivers, it is not needed. +- The `read` method should return the string version of the session data associated with the given `$sessionId`. There is no need to do any serialization or other encoding when retrieving or storing session data in your driver, as Laravel will perform the serialization for you. +- The `write` method should write the given `$data` string associated with the `$sessionId` to some persistent storage system, such as MongoDB, Dynamo, etc. Again, you should not perform any serialization - Laravel will have already handled that for you. +- The `destroy` method should remove the data associated with the `$sessionId` from persistent storage. +- The `gc` method should destroy all session data that is older than the given `$lifetime`, which is a UNIX timestamp. For self-expiring systems like Memcached and Redis, this method may be left empty. +
    - composer dump-autoload + +#### Registering The Driver - php artisan migrate +Once your driver has been implemented, you are ready to register it with the framework. To add additional drivers to Laravel's session backend, you may use the `extend` method on the `Session` [facade](/docs/{{version}}/facades). You should call the `extend` method from the `boot` method of a [service provider](/docs/{{version}}/providers). You may do this from the existing `AppServiceProvider` or create an entirely new provider: - -## Session Drivers + **မှတ်ချက်:** array driver သည် [unit tests](testing.md) အတွက် အသုံးပြုခြင်း ဖြစ်ပြီး တကယ့် session data အတွက် အသုံးပြုခြင်း မဟုတ်ပေ။ + /** + * Register bindings in the container. + * + * @return void + */ + public function register() + { + // + } + } +Once the session driver has been registered, you may use the `mongo` driver in your `config/session.php` configuration file. diff --git a/ssh.md b/ssh.md deleted file mode 100755 index c069e12..0000000 --- a/ssh.md +++ /dev/null @@ -1,263 +0,0 @@ -# SSH - -- [Configuration](#configuration) -- [Basic Usage](#basic-usage) -- [Tasks](#tasks) -- [SFTP Downloads](#sftp-downloads) -- [SFTP Uploads](#sftp-uploads) -- [Tailing Remote Logs](#tailing-remote-logs) -- [Envoy Task Runner](#envoy-task-runner) - - -## Configuration - -Laravel includes a simple way to SSH into remote servers and run commands, allowing you to easily build Artisan tasks that work on remote servers. The `SSH` facade provides the access point to connecting to your remote servers and running commands. - -The configuration file is located at `app/config/remote.php`, and contains all of the options you need to configure your remote connections. The `connections` array contains a list of your servers keyed by name. Simply populate the credentials in the `connections` array and you will be ready to start running remote tasks. Note that the `SSH` can authenticate using either a password or an SSH key. - -> **Note:** Need to easily run a variety of tasks on your remote server? Check out the [Envoy task runner](#envoy-task-runner)! - - -## Basic Usage - -#### Running Commands On The Default Server - -To run commands on your `default` remote connection, use the `SSH::run` method: - - SSH::run(array( - 'cd /var/www', - 'git pull origin master', - )); - -#### Running Commands On A Specific Connection - -Alternatively, you may run commands on a specific connection using the `into` method: - - SSH::into('staging')->run(array( - 'cd /var/www', - 'git pull origin master', - )); - -#### Catching Output From Commands - -You may catch the "live" output of your remote commands by passing a Closure into the `run` method: - - SSH::run($commands, function($line) - { - echo $line.PHP_EOL; - }); - -## Tasks - - -If you need to define a group of commands that should always be run together, you may use the `define` method to define a `task`: - - SSH::into('staging')->define('deploy', array( - 'cd /var/www', - 'git pull origin master', - 'php artisan migrate', - )); - -Once the task has been defined, you may use the `task` method to run it: - - SSH::into('staging')->task('deploy', function($line) - { - echo $line.PHP_EOL; - }); - - -## SFTP Downloads - -The `SSH` class includes a simple way to download files using the `get` and `getString` methods: - - SSH::into('staging')->get($remotePath, $localPath); - - $contents = SSH::into('staging')->getString($remotePath); - - -## SFTP Uploads - -The `SSH` class also includes a simple way to upload files, or even strings, to the server using the `put` and `putString` methods: - - SSH::into('staging')->put($localFile, $remotePath); - - SSH::into('staging')->putString($remotePath, 'Foo'); - - -## Tailing Remote Logs - -Laravel includes a helpful command for tailing the `laravel.log` files on any of your remote connections. Simply use the `tail` Artisan command and specify the name of the remote connection you would like to tail: - - php artisan tail staging - - php artisan tail staging --path=/path/to/log.file - - -## Envoy Task Runner - -- [Installation](#envoy-installation) -- [Running Tasks](#envoy-running-tasks) -- [Multiple Servers](#envoy-multiple-servers) -- [Parallel Execution](#envoy-parallel-execution) -- [Task Macros](#envoy-task-macros) -- [Notifications](#envoy-notifications) -- [Updating Envoy](#envoy-updating-envoy) - -Laravel Envoy provides a clean, minimal syntax for defining common tasks you run on your remote servers. Using a [Blade](templates#blade-templating.md) style syntax, you can easily setup tasks for deployment, Artisan commands, and more. - -> **Note:** Envoy requires PHP version 5.4 or greater, and only runs on Mac / Linux operating systems. - - -### Installation - -First, install Envoy using the Composer `global` command: - - composer global require "laravel/envoy=~1.0" - -Make sure to place the `~/.composer/vendor/bin` directory in your PATH so the `envoy` executable is found when you run the `envoy` command in your terminal. - -Next, create an `Envoy.blade.php` file in the root of your project. Here's an example to get you started: - - @servers(['web' => '192.168.1.1']) - - @task('foo', ['on' => 'web']) - ls -la - @endtask - -As you can see, an array of `@servers` is defined at the top of the file. You can reference these servers in the `on` option of your task declarations. Within your `@task` declarations you should place the Bash code that will be run on your server when the task is executed. - -The `init` command may be used to easily create a stub Envoy file: - - envoy init user@192.168.1.1 - - -### Running Tasks - -To run a task, use the `run` command of your Envoy installation: - - envoy run foo - -If needed, you may pass variables into the Envoy file using command line switches: - - envoy run deploy --branch=master - -You may use the options via the Blade syntax you are used to: - - @servers(['web' => '192.168.1.1']) - - @task('deploy', ['on' => 'web']) - cd site - git pull origin {{ $branch }} - php artisan migrate - @endtask - -#### Bootstrapping - -You may use the ```@setup``` directive to declare variables and do general PHP work inside the Envoy file: - - @setup - $now = new DateTime(); - - $environment = isset($env) ? $env : "testing"; - @endsetup - -You may also use ```@include``` to include any PHP files: - - @include('vendor/autoload.php'); - - -### Multiple Servers - -You may easily run a task across multiple servers. Simply list the servers in the task declaration: - - @servers(['web-1' => '192.168.1.1', 'web-2' => '192.168.1.2']) - - @task('deploy', ['on' => ['web-1', 'web-2']]) - cd site - git pull origin {{ $branch }} - php artisan migrate - @endtask - -By default, the task will be executed on each server serially. Meaning, the task will finish running on the first server before proceeding to execute on the next server. - - -### Parallel Execution - -If you would like to run a task across multiple servers in parallel, simply add the `parallel` option to your task declaration: - - @servers(['web-1' => '192.168.1.1', 'web-2' => '192.168.1.2']) - - @task('deploy', ['on' => ['web-1', 'web-2'], 'parallel' => true]) - cd site - git pull origin {{ $branch }} - php artisan migrate - @endtask - - -### Task Macros - -Macros allow you to define a set of tasks to be run in sequence using a single command. For instance: - - @servers(['web' => '192.168.1.1']) - - @macro('deploy') - foo - bar - @endmacro - - @task('foo') - echo "HELLO" - @endtask - - @task('bar') - echo "WORLD" - @endtask - -The `deploy` macro can now be run via a single, simple command: - - envoy run deploy - - - -### Notifications - -#### HipChat - -After running a task, you may send a notification to your team's HipChat room using the simple `@hipchat` directive: - - @servers(['web' => '192.168.1.1']) - - @task('foo', ['on' => 'web']) - ls -la - @endtask - - @after - @hipchat('token', 'room', 'Envoy') - @endafter - -You can also specify a custom message to the hipchat room. Any variables declared in ```@setup``` or included with ```@include``` will be available for use in the message: - - @after - @hipchat('token', 'room', 'Envoy', "$task ran on [$environment]") - @endafter - -This is an amazingly simple way to keep your team notified of the tasks being run on the server. - -#### Slack - -The following syntax may be used to send a notification to [Slack](https://slack.com): - - @after - @slack('team', 'token', 'channel') - @endafter - - -### Updating Envoy - -To update Envoy, simply run the `self-update` command: - - envoy self-update - -If your Envoy installation is in `/usr/local/bin`, you may need to use `sudo`: - - sudo envoy self-update diff --git a/structure.md b/structure.md new file mode 100644 index 0000000..f9952c8 --- /dev/null +++ b/structure.md @@ -0,0 +1,160 @@ +# Directory Structure + +- [Introduction](#introduction) +- [The Root Directory](#the-root-directory) + - [The `app` Directory](#the-root-app-directory) + - [The `bootstrap` Directory](#the-bootstrap-directory) + - [The `config` Directory](#the-config-directory) + - [The `database` Directory](#the-database-directory) + - [The `public` Directory](#the-public-directory) + - [The `resources` Directory](#the-resources-directory) + - [The `routes` Directory](#the-routes-directory) + - [The `storage` Directory](#the-storage-directory) + - [The `tests` Directory](#the-tests-directory) + - [The `vendor` Directory](#the-vendor-directory) +- [The App Directory](#the-app-directory) + - [The `Console` Directory](#the-console-directory) + - [The `Events` Directory](#the-events-directory) + - [The `Exceptions` Directory](#the-exceptions-directory) + - [The `Http` Directory](#the-http-directory) + - [The `Jobs` Directory](#the-jobs-directory) + - [The `Listeners` Directory](#the-listeners-directory) + - [The `Mail` Directory](#the-mail-directory) + - [The `Notifications` Directory](#the-notifications-directory) + - [The `Policies` Directory](#the-policies-directory) + - [The `Providers` Directory](#the-providers-directory) + + +## Introduction + +The default Laravel application structure is intended to provide a great starting point for both large and small applications. Of course, you are free to organize your application however you like. Laravel imposes almost no restrictions on where any given class is located - as long as Composer can autoload the class. + +#### Where Is The Models Directory? + +When getting started with Laravel, many developers are confused by the lack of a `models` directory. However, the lack of such a directory is intentional. We find the word "models" ambiguous since it means many different things to many different people. Some developers refer to an application's "model" as the totality of all of its business logic, while others refer to "models" as classes that interact with a relational database. + +For this reason, we choose to place Eloquent models in the `app` directory by default, and allow the developer to place them somewhere else if they choose. + + +## The Root Directory + + +#### The App Directory + +The `app` directory, as you might expect, contains the core code of your application. We'll explore this directory in more detail soon; however, almost all of the classes in your application will be in this directory. + + +#### The Bootstrap Directory + +The `bootstrap` directory contains files that bootstrap the framework and configure autoloading. This directory also houses a `cache` directory which contains framework generated files for performance optimization such as the route and services cache files. + + +#### The Config Directory + +The `config` directory, as the name implies, contains all of your application's configuration files. It's a great idea to read through all of these files and familiarize yourself with all of the options available to you. + + +#### The Database Directory + +The `database` directory contains your database migration and seeds. If you wish, you may also use this directory to hold an SQLite database. + + +#### The Public Directory + +The `public` directory contains the `index.php` file, which is the entry point for all requests entering your application. This directory also houses your assets such as images, JavaScript, and CSS. + + +#### The Resources Directory + +The `resources` directory contains your views as well as your raw, un-compiled assets such as LESS, SASS, or JavaScript. This directory also houses all of your language files. + + +#### The Routes Directory + +The `routes` directory contains all of the route definitions for your application. By default, three route files are included with Laravel: `web.php`, `api.php`, and `console.php`. + +The `web.php` file contains routes that the `RouteServiceProvider` places in the `web` middleware group, which provides session state, CSRF protection, and cookie encryption. If your application does not offer a stateless, RESTful API, all of your routes will most likely be defined in the `web.php` file. + +The `api.php` file contains routes that the `RouteServiceProvider` places in the `api` middleware group, which provides rate limiting. These routes are intended to be stateless, so requests entering the application through these routes are intended to be authenticated via tokens and will not have access to session state. + +The `console.php` file is where you may define all of your Closure based console commands. Each Closure is bound to a command instance allowing a simple approach to interacting with each command's IO methods. Even though this file does not define HTTP routes, it defines console based entry points (routes) into your application. + + +#### The Storage Directory + +The `storage` directory contains your compiled Blade templates, file based sessions, file caches, and other files generated by the framework. This directory is segregated into `app`, `framework`, and `logs` directories. The `app` directory may be used to store any files generated by your application. The `framework` directory is used to store framework generated files and caches. Finally, the `logs` directory contains your application's log files. + +The `storage/app/public` directory may be used to store user-generated files, such as profile avatars, that should be publicly accessible. You should create a symbolic link at `public/storage` which points to this directory. You may create the link using the `php artisan storage:link` command. + + +#### The Tests Directory + +The `tests` directory contains your automated tests. An example [PHPUnit](https://phpunit.de/) is provided out of the box. Each test class should be suffixed with the word `Test`. You may run your tests using the `phpunit` or `php vendor/bin/phpunit` commands. + + +#### The Vendor Directory + +The `vendor` directory contains your [Composer](https://getcomposer.org) dependencies. + + +## The App Directory + +The majority of your application is housed in the `app` directory. By default, this directory is namespaced under `App` and is autoloaded by Composer using the [PSR-4 autoloading standard](http://www.php-fig.org/psr/psr-4/). + +The `app` directory contains a variety of additional directories such as `Console`, `Http`, and `Providers`. Think of the `Console` and `Http` directories as providing an API into the core of your application. The HTTP protocol and CLI are both mechanisms to interact with your application, but do not actually contain application logic. In other words, they are simply two ways of issuing commands to your application. The `Console` directory contains all of your Artisan commands, while the `Http` directory contains your controllers, middleware, and requests. + +A variety of other directories will be generated inside the `app` directory as you use the `make` Artisan commands to generate classes. So, for example, the `app/Jobs` directory will not exist until you execute the `make:job` Artisan command to generate a job class. + +> {tip} Many of the classes in the `app` directory can be generated by Artisan via commands. To review the available commands, run the `php artisan list make` command in your terminal. + + +#### The Console Directory + +The `Console` directory contains all of the custom Artisan commands for your application. These commands may be generated using the `make:command` command. This directory also houses your console kernel, which is where your custom Artisan commands are registered and your [scheduled tasks](/docs/{{version}}/scheduling) are defined. + + +#### The Events Directory + +This directory does not exist by default, but will be created for you by the `event:generate` and `make:event` Artisan commands. The `Events` directory, as you might expect, houses [event classes](/docs/{{version}}/events). Events may be used to alert other parts of your application that a given action has occurred, providing a great deal of flexibility and decoupling. + + +#### The Exceptions Directory + +The `Exceptions` directory contains your application's exception handler and is also a good place to place any exceptions thrown by your application. If you would like to customize how your exceptions are logged or rendered, you should modify the `Handler` class in this directory. + + +#### The Http Directory + +The `Http` directory contains your controllers, middleware, and form requests. Almost all of the logic to handle requests entering your application will be placed in this directory. + + +#### The Jobs Directory + +This directory does not exist by default, but will be created for you if you execute the `make:job` Artisan command. The `Jobs` directory houses the [queueable jobs](/docs/{{version}}/queues) for your application. Jobs may be queued by your application or run synchronously within the current request lifecycle. Jobs that run synchronously during the current request are sometimes referred to as "commands" since they are an implementation of the [command pattern](https://en.wikipedia.org/wiki/Command_pattern). + + +#### The Listeners Directory + +This directory does not exist by default, but will be created for you if you execute the `event:generate` or `make:listener` Artisan commands. The `Listeners` directory contains the classes that handle your [events](/docs/{{version}}/events). Event listeners receive an event instance and perform logic in response to the event being fired. For example, a `UserRegistered` event might be handled by a `SendWelcomeEmail` listener. + + +#### The Mail Directory + +This directory does not exist by default, but will be created for you if you execute the `make:mail` Artisan command. The `Mail` directory contains all of your classes that represent emails sent by your application. Mail objects allow you to encapsulate all of the logic of building an email in a single, simple class that may be sent using the `Mail::send` method. + + +#### The Notifications Directory + +This directory does not exist by default, but will be created for you if you execute the `make:notification` Artisan command. The `Notifications` directory contains all of the "transactional" notifications that are sent by your application, such as simple notifications about events that happen within your application. Laravel's notification features abstracts sending notifications over a variety of drivers such as email, Slack, SMS, or stored in a database. + + +#### The Policies Directory + +This directory does not exist by default, but will be created for you if you execute the `make:policy` Artisan command. The `Policies` directory contains the authorization policy classes for your application. Policies are used to determine if a user can perform a given action against a resource. For more information, check out the [authorization documentation](/docs/{{version}}/authorization). + + +#### The Providers Directory + +The `Providers` directory contains all of the [service providers](/docs/{{version}}/providers) for your application. Service providers bootstrap your application by binding services in the service container, registering events, or performing any other tasks to prepare your application for incoming requests. + +In a fresh Laravel application, this directory will already contain several providers. You are free to add your own providers to this directory as needed. diff --git a/summary.md b/summary.md deleted file mode 100755 index 16e836e..0000000 --- a/summary.md +++ /dev/null @@ -1,47 +0,0 @@ -- [Laravel နိဒါန်း](introduction.md) - - [Laravel မိတ်ဆက်](introduction.md) - - [Laravel အကျဉ်းချုပ်](quick.md) - - [Release Notes](releases.md) - - [Upgrade Guide](upgrade.md) -- [Laravel ကိုစတင်လေ့လာခြင်း (အခြေခံ)](installation.md) - - [Laravel install လုပ်ခြင်း](installation.md) - - [Configuration လုပ်ခြင်း](configuration.md) - - [Laravel ရဲ့ Official Development Homestead အကြောင်း](homestead.md) - - [Request Lifecycle ](lifecycle.md) - - [Route လုပ်ခြင်းအကြောင်း](routing.md) - - [Requests နှင့် Input များအကြောင်း ](requests.md) - - [Views နှင့် Responses များအကြောင်း](responses.md) - - [Controllers များအကြောင်း](controllers.md) - - [Errors နှင့် Logging များအကြောင်း](errors.md) -- [Laravel ကိုလေ့လာခြင်း (အဆင့်မြင့်)](security.md) - - [Authentication](security.md) - - [Billing](billing.md) - - [Cache](cache.md) - - [Core Extension](extending.md) - - [Events](events.md) - - [Facades](facades.md) - - [Forms & HTML](html.md) - - [Helpers](helpers.md) - - [IoC Container](ioc.md) - - [Localization](localization.md) - - [Mail](mail.md) - - [Package Development](packages.md) - - [Pagination](pagination.md) - - [Queues](queues.md) - - [Security](security.md) - - [Session](session.md) - - [SSH](ssh.md) - - [Templates](templates.md) - - [Unit Testing](testing.md) - - [Validation](validation.md) -- [Database](database.md) - - [အခြေခံ အသုံးပြုပုံ](database.md) - - [Query Builder](queries.md) - - [Eloquent ORM](eloquent.md) - - [Schema Builder](schema.md) - - [Migrations & Seeding](migrations.md) - - [Redis](redis.md) -- [Artisan CLI](artisan.md) - - [Overview](artisan.md) - - [Development](commands.md) -- [Contributing](contributing.md) \ No newline at end of file diff --git a/templates.md b/templates.md deleted file mode 100755 index 243a75e..0000000 --- a/templates.md +++ /dev/null @@ -1,180 +0,0 @@ -# Templates - -- [Controller Layouts](#controller-layouts) -- [Blade Templating](#blade-templating) -- [Other Blade Control Structures](#other-blade-control-structures) -- [Extending Blade](#extending-blade) - - -## Controller Layouts - -Laravel မှာအသုံးပြုသော templates ပုံစံများထဲကတစ်ခုကတော့ controller layouts ကနေအသုံးပြုတဲ့ပုံစံဖြစ်ပါတယ်။ `layout` property ကို controller မှာသတ်မှတ်လိုက်တာနဲ့ view ဖိုဒါထဲမှာ ကြိုတင်သတ်မှတ်ပြင်ဆင်ထားတဲ့ view ဖိုင်ကို သင့်အတွက်ယူဆောင်ပေးပါလိမ့်မယ်။ ပြီးရင်တော့ controller ကနေညွှန်ကြားလာတဲ့တဲ့ ညွှန်ကြားချက်တွကို လက်ခံဆောင်ရွက်ပေးမှာဖြစ်ပါတယ်။ - -#### Controller တွင် Layout ကိုသတ်မှတ်ခြင်း - - class UserController extends BaseController { - - /** - * The layout that should be used for responses. - */ - protected $layout = 'layouts.master'; - - /** - * Show the user profile. - */ - public function showProfile() - { - $this->layout->content = View::make('user.profile'); - } - - } - - -## Blade Templating - -Laravel မှာပါတဲ့ template ပုံစံနောက်တစ်ခုဖြစ်တဲ့ Blade ဆိုတာကတော့ ရိုးရှင်းပြီး၊ စွမ်းဆောင်ရည်ပြည့်ဝတဲ့ လုပ်ဆောင်ချက်တွေအများကြီးပါတဲ့ template engine တစ်ခုဖြစ်ပါတယ်။ Blade ရဲ့ပုံစံက ပင်မ _template_ မှာတည်ဆောက်ထားတဲ့ပုံစံကို ထပ်ပွားယူပြီး(_inheritance_) အပြောင်းအလဲလုပ်ချင်တဲ့နေရာတွေထဲကို (_section_) လိုအပ်သလို ပြုပြင်ပြောင်းလဲနိုင်တဲ့ ပုံစံဖြစ်ပါတယ်။ Blade template ကိုအသုံးပြုချင်ရင်တော့ `.blade.php` extension နဲ့အသုံးပြုရမှာပါ။ - -#### Blade ပုံစံသတ်မှတ်ခြင်း - - - - - - @section('sidebar') - This is the master sidebar. - @show - -
    - @yield('content') -
    - - - -#### Blade ပုံစံကို အသုံးပြုခြင်း - - @extends('layouts.master') - - @section('sidebar') - @parent - -

    This is appended to the master sidebar.

    - @stop - - @section('content') -

    This is my body content.

    - @stop - -အပေါ်မှာပြထားတဲ့ဥပမာမှာ ပင်မ template ပုံစံကို `extend` လုပ်ယူပြီး ပင်မ layout ထဲက section နေရာကို ထပ်ထည့်ထားတာကို သတိပြုပါ။ ပင်မ layout ထဲမှာ ကြိုတင်သတ်မှတ်ထားတဲ့ အချက်အလက်တွေကို chile view ထဲမှာ ထပ်သုံးချင်ရင် `@parent` ဆိုတဲ့ ညွှန်ကြားချက်ကိုအသုံးပြုနိုင်ပါတယ်။ Sidebar နဲ့ footer ကဲ့သို့သော အပိုင်းတွေအတွက် လိုအပ်တဲ့ အချက်အလက်တွေကို ထပ်ထည့်နိုင်တဲ့ လုပ်ဆောင်ချက်တစ်ခုဖြစ်ပါတယ်။ - -တစ်ခါတစ်ရံ `@section` သတ်မှတ်ထား / မထား မသေချာဘူး `@yield` နဲ့ဆွဲယူထားတဲ့ နေရာထဲကိုလဲ default value တစ်ခု ထည့်ချင်တယ်ဆိုရင် ဒုတိယ argument အနေနဲ့ ထည့်ပေးလိုက်ရင် ရပါတယ်။ - - @yield('section', 'Default Content'); - - -## Blade တွင်အသုံးပြုနိုင်သော အခြား control structures များ - -#### အချက်အလက်ထုတ်ပြခြင်း - - Hello, {{{ $name }}}. - - The current UNIX timestamp is {{{ time() }}}. - -#### အချက်အလက် ရှိ/မရှိ စစ်ဆေးပြီးမှ ထုတ်ပြခြင်း - -တစ်ခါတစ်ရံမှာ အချက်အလက်တစ်ခုကိုထုတ်ပြချင်သော်လည်း အဲ့ဒီ အချက်အလက်ထည့်ထားတဲ့ variable ကို အသုံးပြုထားခြင်း ရှိ/မရှိ မသေချာတဲ့ အခြေအနေမျိုးမှာ ပုံမှန်ဆိုရင် အောက်ပါအတိုင်း အသုံးပြုကြပါတယ်။ - - {{{ isset($name) ? $name : 'Default' }}} - -အဲ့ဒီပုံစံကို Blade နဲ့လွယ်လွယ်ကူကူပဲရေးနိုင်ပါတယ်... အောက်မှာရေးထားတဲ့ပုံစံကိုကြည့်လိုက်ပါ။ - - {{{ $name or 'Default' }}} - -#### တွန့်ကွင်း (Curly Braces) နှင့်အုပ်ထားသော စာသားများအတိုင်း ထုတ်ပြခြင်း - -တွန့်ကွင်း (curly braces) အုပ်ထားတဲ့ စာသားများကို ထုတ်ပြဖို့ လိုအပ်လျှင်တော့ blade ပုံစံကို ရှေ့မှာ `@` သင်္ကေတ နဲ့ခံပြီး အသုံးပြုနိုင်ပါတယ်။ - - @{{ This will not be processed by Blade }} - -အသုံးပြုသူဆီက ဝင်လာမဲ့ အချက်အလက်တွေကို escape သို့မဟုတ် purified လုပ်သင့်ပါတယ်။ အဲ့လိုပြုလုပ်ဖို့အတွက် တွန့်ကွင်းသုံးခု (triple curly brace) ကိုအသုံးပြုနိုင်ပါတယ်။ - - Hello, {{{ $name }}}. - -အကယ်၍ escape မလုပ်ချင်ဘူးဆိုရင်တော့ တွန့်ကွင်း နှစ်ခု (double curly braces) ကိုအသုံးပြုနိုင်ပါတယ်။ - - Hello, {{ $name }}. - -> **သတိပြုရန်:** Application ကိုအသုံးပြုုသူဆီကလာမဲ့ အချက်အလက်တွေကိုထုတ်ပြတဲ့ကိစ္စကို အထူးဂရုစိုက်ဖို့ လိုအပ်ပါတယ်။ အဲ့ဒါကြောင့် HTML entities တွေကို escape ပြုလုပ်ဖို့အတွက် တွန့်ကွင်းသုံးခု (triple curly brace) ကိုအမြဲတမ်းအသုံးပြုသင့်ပါတယ်။ - -#### If Statements - - @if (count($records) === 1) - I have one record! - @elseif (count($records) > 1) - I have multiple records! - @else - I don't have any records! - @endif - - @unless (Auth::check()) - You are not signed in. - @endunless - -#### Loops - - @for ($i = 0; $i < 10; $i++) - The current value is {{ $i }} - @endfor - - @foreach ($users as $user) -

    This is user {{ $user->id }}

    - @endforeach - - @while (true) -

    I'm looping forever.

    - @endwhile - -#### Including Sub-Views - - @include('view.name') - -Include လုပ်ထားတဲ့ view တွေဆီကိုလဲ အချက်အလက်တွေကို passing လုပ်လို့ရပါတယ်။ - - @include('view.name', array('some'=>'data')) - -#### Overwriting Sections - -ပုံမှန်ဆိုရင် sections ဟာ ယခင်ရှိပီးသား အချက်အလက်တွေနဲ့အတူ နောက်ထပ် ထပ်ထည့်လာတဲ့ အချက်အလက်တွေကို ပေါင်းထည့်လိုက်တာဖြစ်ပါတယ်။ အကယ်၍ ယခင်အချက်အလက်တွေကို ဖျက်ပြစ်ပီး နောက်ထပ် ထပ်ထည့်လိုက်တဲ့ အချက်အလက်ကိုပဲ အသုံးပြုချင်ရင်တော့ `overwrite` ကိုအသုံးပြုနိုင်ပါတယ်။ - - @extends('list.item.container') - - @section('list.item.content') -

    This is an item of type {{ $item->type }}

    - @overwrite - -#### Displaying Language Lines - - @lang('language.line') - - @choice('language.line', 1); - -#### Comments - - {{-- This comment will not be in the rendered HTML --}} - - -## Extending Blade - -Blade ကိုအသုံးပြုပြီး စိတ်ကြိုက် control structure တွေကိုပြုလုပ်နိုင်ပါတယ်။ blade file ကို compile လုပ်ပီးတဲ့အခါ၊ သတ်မှတ်ထားတဲ့ စိတ်ကြိုက် control structure တွေကို view အတွက် အချက်အလက်တွေနဲ့အတူ ခေါ်ယူသုံးစွဲပါတယ်။ ရိုးရှင်းလွယ်ကူတဲ့ `str_replace` လိုကိစ္စတွေတင်မက ပိုပြီးရှုပ်ထွေးတဲ့ ကိစ္စတွေအထိ ကိုင်တွယ်ဖြေရှင်းနိုင်ပါတယ်။ - -Blade compiler မှာ `createMatcher` နဲ့ `create:lainMatcher` ဆိုပြီး helper methods နှစ်ခု ရှိပါတယ်။ အဲ့ဒီ methods တွေကနေ စိတ်ကြိုက် control structure တွေပြုလုပ်ဖို့ လိုအပ်တဲ့ အရာတွေကိုပြုလုပ်ပေးပါတယ်။ - -`createPlainMatcher` method ကို `@endif` တို့ `@stop` တို့လို arguments တွေမပါတာအတွက် အသုံးပြုပြီး၊ `createMatcher` method ကိုတော့ arguments ပါတာတွေပြုလုပ်ဖို့အတွက် အသုံးပြုပါတယ်။ - -အောက်ပါ ဥပမာကတော့ `@datatime($var)` ကို ပြုလုပ်ထားတာပါ။ အဲ့ဒီ directive မှာပါတဲ့ `$var` ရဲ့ တန်ဖိုးကို `->format()` အသုံးပြုပြီး အလွယ်တကူ ခေါ်သုံးနိုင်ပါတယ်။ - - Blade::extend(function($view, $compiler) - { - $pattern = $compiler->createMatcher('datetime'); - - return preg_replace($pattern, '$1format('m/d/Y H:i'); ?>', $view); - }); diff --git a/testing.md b/testing.md old mode 100755 new mode 100644 index 27d631e..7a6abc4 --- a/testing.md +++ b/testing.md @@ -1,222 +1,57 @@ -# Unit Testing +# Testing: Getting Started - [Introduction](#introduction) -- [Defining & Running Tests](#defining-and-running-tests) -- [Test Environment](#test-environment) -- [Calling Routes From Tests](#calling-routes-from-tests) -- [Mocking Facades](#mocking-facades) -- [Framework Assertions](#framework-assertions) -- [Helper Methods](#helper-methods) -- [Refreshing The Application](#refreshing-the-application) +- [Environment](#environment) +- [Creating & Running Tests](#creating-and-running-tests) ## Introduction -Laravel ဟာ unit testing ကို အဓိကအခြေခံထားပြီး တည်ဆောက်ထားတာ ဖြစ်ပါတယ်။ ဒါ့အပြင် testing framework ဖြစ်တဲ့ PHPUnit support လည်း ပါဝင်ပါတဲ့အတွက် application ကို စ setup လုပ်ကတည်းက `phpunit.xml` ဖိုင်ကို တစ်ခါတည်း setup လုပ်ပေးထားမှာ ဖြစ်ပါတယ်။ PHPUnit အပြင် Laravel မှာ Symfony ရဲ့ HttpKernel, DomCrawler နှင့် BrowserKit တို့ ပါဝင်တဲ့အတွက် testing လုပ်ရာမှာ application ရဲ့ views တွေကို web browser တစ်ခုကဲ့သို့ simulate လုပ်နိုင်ပြီး စစ်ဆေးပြုပြင်နိုင်မှာဖြစ်ပါတယ်။ +Laravel is built with testing in mind. In fact, support for testing with PHPUnit is included out of the box and a `phpunit.xml` file is already setup for your application. The framework also ships with convenient helper methods that allow you to expressively test your applications. -ဥပမာ အနေဖြင့် test ဖိုင်တစ်ခုလည်း `app/tests` folder ထဲမှာပါဝင်ပါတယ်။ Laravel appilcation တစ်ခုကို install လုပ်ပြီးပါက `phpunit` command ကို run ယုံဖြင့် application ရဲ့ tests များကို run နိုင်မှာဖြစ်ပါတယ်။ +By default, your application's `tests` directory contains two directories: `Feature` and `Unit`. Unit tests are tests that focus on a very small, isolated portion of your code. In fact, most unit tests probably focus on a single method. Feature tests may test a larger portion of your code, including how several objects interact with each other or even a full HTTP request to a JSON endpoint. +An `ExampleTest.php` file is provided in both the `Feature` and `Unit` test directories. After installing a new Laravel application, simply run `phpunit` on the command line to run your tests. - -## Defining & Running Tests (Tests များ သတ်မှတ်ခြင်းနှင့် Run ခြင်း) + +## Environment -Test case ကိုဖန်တီးဖို့ `app/tests` folder ထဲမှာ file အသစ်တစ်ခု ပြုလုပ်ပါ။ class ကတော့ `TestCase` class ကို extend ရမှာဖြစ်ပါတယ်။ ထို့နောက်မှာတော့ သင်နှစ်သက်သလို test methods များကို PHPUnit ကိုအသုံးပြုပြီး ဖန်တီးနိုင်ပြီ ဖြစ်ပါတယ်။ +When running tests via `phpunit`, Laravel will automatically set the configuration environment to `testing` because of the environment variables defined in the `phpunit.xml` file. Laravel also automatically configures the session and cache to the `array` driver while testing, meaning no session or cache data will be persisted while testing. +You are free to define other testing environment configuration values as necessary. The `testing` environment variables may be configured in the `phpunit.xml` file, but make sure to clear your configuration cache using the `config:clear` Artisan command before running your tests! -#### Test Class ဥပမာ + +## Creating & Running Tests - class FooTest extends TestCase { +To create a new test case, use the `make:test` Artisan command: - public function testSomethingIsTrue() - { - $this->assertTrue(true); - } + // Create a test in the Feature directory... + php artisan make:test UserTest - } + // Create a test in the Unit directory... + php artisan make:test UserTest --unit -သင့် application မှ tests များကို terminal မှ `phpunit` command ရိုက်ပြီး run နိုင်ပါတယ်။ +Once the test has been generated, you may define test methods as you normally would using PHPUnit. To run your tests, simply execute the `phpunit` command from your terminal: + **သတိ:** ကိုယ့်ဟာကို `setUp` method ရေးထားပါက `parent::setUp` ကို ခေါ်ဖို့ သတိရပါ။ + namespace Tests\Unit; - -## Test Environment + use Tests\TestCase; + use Illuminate\Foundation\Testing\DatabaseMigrations; + use Illuminate\Foundation\Testing\DatabaseTransactions; -unit tests များကို run နေစဉ် Laravel က configuration environment ကို `testing` သို့ အလိုအလျောက် ပြောင်းထားမှာဖြစ်ပါတယ်။ ထို့အပြင် Laravel ရဲ့ test environment ထဲမှာ `session` နှင့် `cache` တို့ရဲ့ configuration files များပါ ပါဝင်မှာဖြစ်ပါတယ်။ ဒီ drivers နှစ်ခုစလုံးကို test environment ထဲမှာ `array` အဖြစ် set ထားမှာဖြစ်ပါတဲ့အတွက် testing လုပ်ပြီးရင်တော့ testing နဲ့ပတ်သက်တဲ့ session သို့မဟုတ် cache data တွေတော့ ပျက်သွားမှာဖြစ်ပါတယ်။ လိုအပ်ရင်လိုအပ်သလို တခြား testing environments တွေကို ဆက်လက်ဖန်တီးလို့လည်း ရပါတယ်။ - - - -## Calling Routes From Tests (Tests များမှ Routes ကိုခေါ်ခြင်း) - -#### Test တစ်ခုမှ Route ကိုခေါ်ခြင်း -`call` method ကိုအသုံးပြု၍ route တစ်ခုခုကို test ကနေ အလွယ်တကူ ခေါ်နိုင်ပါတယ်၊ - - $response = $this->call('GET', 'user/profile'); - - $response = $this->call($method, $uri, $parameters, $files, $server, $content); - -ထို့နောက် `Illuminate\Http\Response` object ကို စစ်ဆေးနိုင်ပါတယ်။ - - $this->assertEquals('Hello World', $response->getContent()); - -#### Test တစ်ခုမှ Controller ကိုခေါ်ခြင်း - -test ကနေ controller ကိုလည်းခေါ်နိုင်ပါတယ်။ - - $response = $this->action('GET', 'HomeController@index'); - - $response = $this->action('GET', 'UserController@profile', array('user' => 1)); - -ဒီ `getContent` method ဟာ response ကနေ evaluated string contents တွေကို ပြန်ပေးမှာဖြစ်ပါတယ်။ သင့်၏ route မှ `View` return ရင်တော့ `original` property ကို အသုံးပြု၍ access လုပ်နိုင်ပါတယ်၊ - - $view = $response->original; - - $this->assertEquals('John', $view['name']); - -HTTPS route တစ်ခုကိုခေါ်လိုပါက `callSecure` method ကို အသုံးပြုနိုင်ပါတယ်။ - - $response = $this->callSecure('GET', 'foo/bar'); - -> **သတိ:** testing environment တွေထဲမှာ route filters တွေကို disable ထားပါတယ်။. ပြန်လည် enable ချင်ရင်တော့, test ထဲမှာ `Route::enableFilters()` ထည့်လိုက်ပါ။ - -### DOM Crawler - -Route ကိုခေါ်၍ DOM Crawler ကိုလက်ခံပြီး ရလာတဲ့ content ကိုစစ်ဆေးနိုင်ပါတယ်။ - - $crawler = $this->client->request('GET', '/'); - - $this->assertTrue($this->client->getResponse()->isOk()); - - $this->assertCount(1, $crawler->filter('h1:contains("Hello World!")')); - -Crawler အသုံးပြုပုံနှင့်ပတ်သက်ပြီး ပိုသိလိုပါက ၎င်းရဲ့[official documentation](http://symfony.com/doc/master/components/dom_crawler.html) ကို ကိုးကားပါ၊ - - -## Mocking Facades (Facades များ အတုပြုလုပ်ခြင်း) - -Testing လုပ်နေစဉ် ရံဖန်ရံခါမှ Laravel ၏ static facade call တွေကို အတုပြုလုပ် (mock) လိုတတ်ပါတယ်။ ဥပမာအနေဖြင့် အောက်ပါ controller action ကိုကြည့်ပါ။ - - public function getIndex() - { - Event::fire('foo', array('name' => 'Dayle')); - - return 'All done!'; - } - -`Event` class သို့ ခေါ်ထားသော call အား facade မှာရှိတဲ့ `shouldReceive` method ဖြင့် အတုပြုလုပ်နိုင်ပါတယ်။ [Mockery](https://github.com/padraic/mockery) mock instance တစ်ခု ပြန်လည် return မှာ ဖြစ်ပါတယ်။ - -#### Facade တစ်ခု အတုပြုလုပ်ခြင်း - - public function testGetIndex() - { - Event::shouldReceive('fire')->once()->with('foo', array('name' => 'Dayle')); - - $this->call('GET', '/'); - } - -> **သတိ:** `Request` facade ကိုတော့ မ mock သင့်ပါဘူး။ အဲဒီအစား pass ချင်တဲ့ input အား `call` method သို့ pass ပြီး test ကို run ပါ။ - - -## Framework Assertions (Framework စစ်ဆေးခြင်းများ) - -Laravel တွင် testing လုပ်ဖို့ အနည်းငယ် ပိုမိုလွယ်ကူသက်သာစေရန် `assert` methods များပါဝင်ပါတယ်။ - -#### Respones များ HTTP status OK ဖြစ်ကြောင်း စစ်ဆေးခြင်း - - public function testMethod() - { - $this->call('GET', '/'); - - $this->assertResponseOk(); - } - -#### အခြား response statuses များအား စစ်ဆေးခြင်း - - $this->assertResponseStatus(403); - -#### responses များ HTTP Redirects များ ဖြစ်ကြောင်း စစ်ဆေးခြင်း - - $this->assertRedirectedTo('foo'); - - $this->assertRedirectedToRoute('route.name'); - - $this->assertRedirectedToAction('Controller@method'); - -#### View တွင် data ရှိကြောင်း စစ်ဆေးခြင်း - - public function testMethod() - { - $this->call('GET', '/'); - - $this->assertViewHas('name'); - $this->assertViewHas('age', $value); - } - -#### Session တွင် data ရှိကြောင်း စစ်ဆေးခြင်း - - public function testMethod() - { - $this->call('GET', '/'); - - $this->assertSessionHas('name'); - $this->assertSessionHas('age', $value); - } - -#### Session တွင် Errors များ စစ်ဆေးခြင်း - - public function testMethod() + class ExampleTest extends TestCase { - $this->call('GET', '/'); - - $this->assertSessionHasErrors(); - - // Asserting the session has errors for a given key... - $this->assertSessionHasErrors('name'); - - // Asserting the session has errors for several keys... - $this->assertSessionHasErrors(array('name', 'age')); + /** + * A basic test example. + * + * @return void + */ + public function testBasicTest() + { + $this->assertTrue(true); + } } -#### Input အဟောင်းများ Data စစ်ဆေးခြင်း - - public function testMethod() - { - $this->call('GET', '/'); - - $this->assertHasOldInput(); - } - - -## Helper Methods (အထောက်အကူ Methods များ) - -Application test လုပ်ရာတွင် ပိုမိုလွယ်ကူစေရန် `TestCase` class တွင် helper methods များပါဝင်ပါတယ်။ - -#### Tests မှ Sessisons data များ ဖန်တီ ခြင်း flush ခြင်း - - $this->session(['foo' => 'bar']); - - $this->flushSession(); - -#### လက်ရှိ authenticated ဖြစ်ပြီးသော User တစ်ယောက်ဖန်တီးခြင်း - -`be` method အား အသုံးပြု၍ လက်ရှိ authenticated ဖြစ်ပြီးသော user တစ်ယောက်ဖန်တီးနိုင်ပါတယ်။ - - $user = new User(array('name' => 'John')); - - $this->be($user); - -Database အား `seed` method အသုံးပြု၍ re-seed ပြုလုပ်နိုင်ပါတယ်။ - -#### Test မှ Database အား Re-seed ပြုလုပ်ခြင်း - - $this->seed(); - - $this->seed($connection); - -Database seeds များပြုလုပ်ခြင်းနှင့် ပတ်သက်၍ documentation ရဲ့ [migrations and seeding](migrations#database-seeding.md) အခန်းမှာ သွားကြည့်နိုင်ပါတယ်။ - - - -## Application အား refresh ပြုလုပ်ခြင်း - -သင်၏ Laravel `Application/IoC Container` အား `$this->app` မှတစ်ဆင့် မည်သည့် test method မှမဆို access နိုင်ပါတယ်။ ဒီ Application instance ဟာ test case တစ်ခုစီ အတွက် ပြန်လည် refresh သွားမှာဖြစ်ပါတယ်။ Application အား သင် သတ်မှတ်ထားသော method တစ်ခုအတွက်သာ refresh ပြုလုပ်ချင်ပါက test method မှ `refreshApplication` method ကို အသုံးပြုနိုင်ပါတယ်။ ဒါဟာ test cases များ စ run ကတည်းက IoC container ထဲမှာရှိတေသာ အပို bindings များ၊ အတုပြုလုပ်ခြင်း (mocks) များအား reset ပြုလုပ်သွားမှာ ဖြစ်ပါတယ်။ \ No newline at end of file +> {note} If you define your own `setUp` method within a test class, be sure to call `parent::setUp`. diff --git a/upgrade.md b/upgrade.md old mode 100755 new mode 100644 index 6f93156..f8dd13a --- a/upgrade.md +++ b/upgrade.md @@ -1,163 +1,462 @@ # Upgrade Guide -- [Upgrading To 4.2 From 4.1](#upgrade-4.2) -- [Upgrading To 4.1.29 From <= 4.1.x](#upgrade-4.1.29) -- [Upgrading To 4.1.26 From <= 4.1.25](#upgrade-4.1.26) -- [Upgrading To 4.1 From 4.0](#upgrade-4.1) +- [Upgrading To 5.4.0 From 5.3](#upgrade-5.4.0) - -## Upgrading To 4.2 From 4.1 + +## Upgrading To 5.4.0 From 5.3 -### PHP 5.4+ +#### Estimated Upgrade Time: 1-2 Hours -Laravel 4.2 requires PHP 5.4.0 or greater. +> {note} We attempt to document every possible breaking change. Since some of these breaking changes are in obscure parts of the framework only a portion of these changes may actually affect your application. -### Encryption Defaults +### Updating Dependencies -Add a new `cipher` option in your `app/config/app.php` configuration file. The value of this option shuold be `MCRYPT_RIJNDAEL_256`. +Update your `laravel/framework` dependency to `5.4.*` in your `composer.json` file. In addition, you should update your `phpunit/phpunit` dependency to `~5.0`. - 'cipher' => MCRYPT_RIJNDAEL_256 +#### Flushing The Cache -This seting may be used to control the default cipher used by the Laravel envryption facilities. +After upgrading all packages, you should run `php artisan view:clear` to avoid Blade errors related to the removal of `Illuminate\View\Factory::getFirstLoop()`. In addition, you may need to run `php artisan route:clear` to flush the route cache. -### Soft Deleting Models Now Use Traits +#### Laravel Cashier -If you are using soft deleting models, the `softDeletes` property has been removed. You should now use the `SoftDeletingTrait` like so: +Laravel Cashier is already compatible with Laravel 5.4. - use Illuminate\Database\Eloquent\SoftDeletingTrait; +#### Laravel Passport - class User extends Eloquent { - use SoftDeletingTrait; - } +Laravel Passport `2.0.0` has been released to provide compatibility with Laravel 5.4 and the [Axios](https://github.com/mzabriskie/axios) JavaScript library. If you are upgrading from Laravel 5.3 and using the pre-built Passport Vue components, you should make sure the Axios library is globally available to your application as `axios`. -You should also manually add the `deleted_at` column to your `dates` property: +#### Laravel Scout - class User extends Eloquent { - use SoftDeletingTrait; +Laravel Scout `3.0.0` has been released to provide compatibility with Laravel 5.4. - protected $dates = ['deleted_at']; - } +#### Laravel Socialite -The API for all soft delete operations remains the same. +Laravel Socialite `3.0.0` has been released to provide compatibility with Laravel 5.4. -### View / Pagination Environment Renamed +#### Laravel Tinker -If you are directly referencing the `Illuminate\View\Environment` class or `Illuminate\Pagination\Environment` class, update your code to reference `Illuminate\View\Factory` and `Illuminate\Pagination\Factory` instead. These two classes have been renamed to better reflect their function. +In order to continue using the `tinker` Artisan command, you should also install the `laravel/tinker` package: -### Additional Parameter On Pagination Presenter + composer require laravel/tinker -If you are extending the `Illuminate\Pagination\Presenter` class, the abstract method `getPageLinkWrapper` signature has changed to add the `rel` argument: +Once the package has been installed, you should add `Laravel\Tinker\TinkerServiceProvider::class` to the `providers` array in your `config/app.php` configuration file. - abstract public function getPageLinkWrapper($url, $page, $rel = null); +#### Guzzle - -## Upgrading To 4.1.29 From <= 4.1.x +Laravel 5.4 requires Guzzle 6.0 or greater. -Laravel 4.1.29 improves the column quoting for all database drivers. This protects your application from some mass assignment vulnerabilities when **not** using the `fillable` property on models. If you are using the `fillable` property on your models to protect against mass assignemnt, your application is not vulerable. However, if you are using `guarded` and are passing a user controlled array into an "update" or "save" type function, you should upgrade to `4.1.29` immediately as your application may be at risk of mass assignment. +### Authorization -To upgrade to Laravel 4.1.29, simply `composer update`. No breaking changes are introduced in this release. +#### The `getPolicyFor` Method - -## Upgrading To 4.1.26 From <= 4.1.25 +Previous, when calling the `Gate::getPolicyFor($class)` method, an exception was thrown if no policy could be found. Now, the method will return `null` if no policy is found for the given class. If you call this method directly, make sure you refactor your code to check for `null`: -Laravel 4.1.26 introduces security improvements for "remember me" cookies. Before this update, if a remember cookie was hijacked by another malicious user, the cookie would remain valid for a long period of time, even after the true owner of the account reset their password, logged out, etc. +```php +$policy = Gate::getPolicyFor($class); -This change requires the addition of a new `remember_token` column to your `users` (or equivalent) database table. After this change, a fresh token will be assigned to the user each time they login to your application. The token will also be refreshed when the user logs out of the application. The implications of this change are: if a "remember me" cookie is hijacked, simply logging out of the application will invalidate the cookie. +if ($policy) { + // code that was previously in the try block +} else { + // code that was previously in the catch block +} +``` -### Upgrade Path +### Blade -First, add a new, nullable `remember_token` of VARCHAR(100), TEXT, or equivalent to your `users` table. +#### `@section` Escaping -Next, if you are using the Eloquent authentication driver, update your `User` class with the following three methods: +In Laravel 5.4, inline content passed to a section is automatically escaped: - public function getRememberToken() - { - return $this->remember_token; - } + @section('title', $content) - public function setRememberToken($value) - { - $this->remember_token = $value; - } +If you would like to render unescaped content in a section, you must declare the section using the traditional "long form" style: - public function getRememberTokenName() - { - return 'remember_token'; - } + @section('title') + {!! $content !!} + @stop -> **Note:** All existing "remember me" sessions will be invalidated by this change, so all users will be forced to re-authenticate with your application. +### Bootstrappers -### Package Maintainers +If you are manually overriding the `$bootstrappers` array on your HTTP or Console kernel, you should rename the `DetectEnvironment` entry to `LoadEnvironmentVariables`. -Two new methods were added to the `Illuminate\Auth\UserProviderInterface` interface. Sample implementations may be found in the default drivers: +### Broadcasting - public function retrieveByToken($identifier, $token); +#### Channel Model Binding - public function updateRememberToken(UserInterface $user, $token); +When defining channel name placeholders in Laravel 5.3, the `*` character is used. In Laravel 5.4, you should define these placeholders using `{foo}` style placeholders, like routes: -The `Illuminate\Auth\UserInterface` also received the three new methods described in the "Upgrade Path". + Broadcast::channel('App.User.{userId}', function ($user, $userId) { + return (int) $user->id === (int) $userId; + }); - -## Upgrading To 4.1 From 4.0 +### Collections -### Upgrading Your Composer Dependency +#### The `every` Method -To upgrade your application to Laravel 4.1, change your `laravel/framework` version to `4.1.*` in your `composer.json` file. +The behavior of the `every` method has been moved to the `nth` method to match the method name defined by Lodash. -### Replacing Files +#### The `random` Method -Replace your `public/index.php` file with [this fresh copy from the repository](https://github.com/laravel/laravel/blob/master/public/index.php). +Calling `$collection->random(1)` will now return a new collection instance with one item. Previously, this would return a single object. This method will only return a single object if no arguments are supplied. -Replace your `artisan` file with [this fresh copy from the repository](https://github.com/laravel/laravel/blob/master/artisan). +### Container -### Adding Configuration Files & Options +#### Binding Classes With Leading Slashes -Update your `aliases` and `providers` arrays in your `app/config/app.php` configuration file. The updated values for these arrays can be found [in this file](https://github.com/laravel/laravel/blob/master/app/config/app.php). Be sure to add your custom and package service providers / aliases back to the arrays. +Binding classes into the container with leading slashes is no longer supported. This feature required a significant amount of string formatting calls to be made within the container. Instead, simply register your bindings without a leading slash: -Add the new `app/config/remote.php` file [from the repository](https://github.com/laravel/laravel/blob/master/app/config/remote.php). + $container->bind('Class\Name', function () { + // + }); -Add the new `expire_on_close` configuration option to your `app/config/session.php` file. The default value should be `false`. + $container->bind(ClassName::class, function () { + // + }); -Add the new `failed` configuration section to your `app/config/queue.php` file. Here are the default values for the section: +#### `make` Method Parameters - 'failed' => array( - 'database' => 'mysql', 'table' => 'failed_jobs', - ), +The container's `make` method no longer accepts a second array of parameters. This feature typically indicates a code smell. Typically, you can always construct the object in another way that is more intuitive. -**(Optional)** Update the `pagination` configuration option in your `app/config/view.php` file to `pagination::slider-3`. +#### Resolving Callbacks -### Controller Updates +The container's `resolving` and `afterResolving` method now must be provided a class name or binding key as the first argument to the method: -If `app/controllers/BaseController.php` has a `use` statement at the top, change `use Illuminate\Routing\Controllers\Controller;` to `use Illuminate\Routing\Controller;`. + $container->resolving('Class\Name', function ($instance) { + // + }); -### Password Reminders Updates + $container->afterResolving('Class\Name', function ($instance) { + // + }); -Password reminders have been overhauled for greater flexibility. You may examine the new stub controller by running the `php artisan auth:reminders-controller` Artisan command. You may also browse the [updated documentation](security#password-reminders-and-reset.md) and update your application accordingly. +#### `share` Method Removed -Update your `app/lang/en/reminders.php` language file to match [this updated file](https://github.com/laravel/laravel/blob/master/app/lang/en/reminders.php). +The `share` method has been removed from the container. This was a legacy method that has not been documented in several years. If you are using this method, you should begin using the `singleton` method instead: -### Environment Detection Updates + $container->singleton('foo', function () { + return 'foo'; + }); -For security reasons, URL domains may no longer be used to detect your application environment. These values are easily spoofable and allow attackers to modify the environment for a request. You should convert your environment detection to use machine host names (`hostname` command on Mac, Linux, and Windows). +### Console -### Simpler Log Files +#### The `Illuminate\Console\AppNamespaceDetectorTrait` Trait -Laravel now generates a single log file: `app/storage/logs/laravel.log`. However, you may still configure this behavior in your `app/start/global.php` file. +If you are directly referencing the `Illuminate\Console\AppNamespaceDetectorTrait` trait, update your code to reference `Illuminate\Console\DetectsApplicationNamespace` instead. -### Removing Redirect Trailing Slash +### Database -In your `bootstrap/start.php` file, remove the call to `$app->redirectIfTrailingSlash()`. This method is no longer needed as this functionality is now handled by the `.htaccess` file included with the framework. +#### Custom Connections -Next, replace your Apache `.htaccess` file with [this new one](https://github.com/laravel/laravel/blob/master/public/.htaccess) that handles trailing slashes. +If you were previously binding a service container binding for a `db.connection.{driver-name}` key in order to resolve a custom database connection instance, you should now use the `Illuminate\Database\Connection::resolverFor` method in the `register` method of your `AppServiceProvider`: -### Current Route Access + use Illuminate\Database\Connection; -The current route is now accessed via `Route::current()` instead of `Route::getCurrentRoute()`. + Connection::resolverFor('driver-name', function ($connection, $database, $prefix, $config) { + // + }); -### Composer Update +#### Fetch Mode -Once you have completed the changes above, you can run the `composer update` function to update your core application files! If you receive class load errors, try running the `update` command with the `--no-scripts` option enabled like so: `composer update --no-scripts`. +Laravel no longer includes the ability to customize the PDO "fetch mode" from your configuration files. Instead, `PDO::FETCH_OBJ` is always used. If you will still like to customize the fetch mode for your application you may listen for the new `Illuminate\Database\Events\StatementPrepared` event: -### Wildcard Event Listeners + Event::listen(StatementPrepared::class, function ($event) { + $event->statement->setFetchMode(...); + }); -The wildcard event listeners no longer append the event to your handler functions parameters. If you require finding the event that was fired you should use `Event::firing()`. +### Eloquent + +#### Date Casts + +The `date` cast now converts the column to a `Carbon` object and calls the `startOfDay` method on the object. If you would like to preserve the time portion of the date, you should use the `datetime` cast. + +#### Foreign Key Conventions + +If the foreign key is not explicitly specified when defining a relationship, Eloquent will now use the table name and primary key name for the related model to build the foreign key. For the vast majority of applications, this is not a change of behavior. For example: + + public function user() + { + return $this->belongsTo(User::class); + } + +Just like previous Laravel releases, this relationship will typically use `user_id` as the foreign key. However, the behavior could be different from previous releases if you are overriding the `getKeyName` method of the `User` model. For example: + + public function getKeyName() + { + return 'key'; + } + +When this is the case, Laravel will now respect your customization and determine the foreign key column name is `user_key` instead of `user_id`. + +#### Has One / Many `createMany` + +The `createMany` method of a `hasOne` or `hasMany` relationship now returns a collection object instead of an array. + +#### Related Model Connections + +Related models will now use the same connection as the parent model. For example, if you execute a query like: + + User::on('example')->with('posts'); + +Eloquent will query the posts table on the `example` connection instead of the default database connection. If you want to read the `posts` relationship from the default connection, you should to explicitly set the model's connection to your application's default connection. + +#### The `hydrate` Method + +If you are currently passing a custom connection name to this method, you should now use the `on` method: + + User::on('connection')->hydrate($records); + +#### `hydrateRaw` Method + +The `Model::hydrateRaw` method has been renamed to `fromQuery`. If you are passing a custom connection name to this method, you should now use the `on` method: + + User::on('connection')->fromQuery('...'); + +#### The `whereKey` method + +The `whereKey($id)` method will now add a "where" clause for the given primary key value. Previously, this would fall into the dynamic "where" clause builder and add a "where" clause for the "key" column. If you used the `whereKey` method to dynamically add a condition for the `key` column you should now use `where('key', ...)` instead. + +#### The `factory` Helper + +Calling `factory(User::class, 1)->make()` or `factory(User::class, 1)->create()` will now return a collection with one item. Previously, this would return a single model. This method will only return a single model if the amount is not supplied. + +### Events + +#### Contract Changes + +If you are manually implementing the `Illuminate\Contracts\Events\Dispatcher` interface in your application or package, you should rename the `fire` method to `dispatch`. + +#### Event Priority + +Support for event handler "priorities" has been removed. This undocumented feature typically indicates an abuse of the event feature. Instead, consider using a series of synchronous method calls. Alternatively, you may dispatch a new event from within the handler of another event in order to ensure that a given event's handler fires after an unrelated handler. + +#### Wildcard Event Handler Signatures + +Wildcard event handlers now receive the event name as their first argument and the array of event data as their second argument. The `Event::firing` method has been removed: + + Event::listen('*', function ($eventName, array $data) { + // + }); + +#### The `kernel.handled` Event + +The `kernel.handled` event is now an object based event using the `Illuminate\Foundation\Http\Events\RequestHandled` class. + +#### The `locale.changed` Event + +The `locale.changed` event is now an object based event using the `Illuminate\Foundation\Events\LocaleUpdated` class. + +#### The `illuminate.log` Event + +The `illuminate.log` event is now an object based event using the `Illuminate\Log\Events\MessageLogged` class. + +### Exceptions + +The `Illuminate\Http\Exception\HttpResponseException` has been renamed to `Illuminate\Http\Exceptions\HttpResponseException`. Note that `Exceptions` is now plural. Likewise, the `Illuminate\Http\Exception\PostTooLargeException` has been renamed to `Illuminate\Http\Exceptions\PostTooLargeException`. + +### Mail + +#### `Class@method` Syntax + +Sending mail using `Class@method` syntax is no longer supported. For example: + + Mail::send('view.name', $data, 'Class@send'); + +If you are sending mail in this way you should convert these calls to [mailables](/docs/{{version}}/mail). + +#### New Configuration Options + +In order to provide support for Laravel 5.4's new Markdown mail components, you should add the following block of configuration to the bottom of your `mail` configuration file: + + 'markdown' => [ + 'theme' => 'default', + + 'paths' => [ + resource_path('views/vendor/mail'), + ], + ], + +#### Queueing Mail With Closures + +In order to queue mail, you now must use a [mailable](/docs/{{version}}/mail). Queuing mail using the `Mail::queue` and `Mail::later` methods no longer supports using Closures to configure the mail message. This feature required the use of special libraries to serialize Closures since PHP does not natively support this feature. + +### Redis + +#### Improved Clustering Support + +Laravel 5.4 introduces improved Redis cluster support. If you are using Redis clusters, you should place your cluster connections inside of a `clusters` configuration option in the Redis portion of your `config/database.php` configuration file: + + 'redis' => [ + + 'client' => 'predis', + + 'options' => [ + 'cluster' => 'redis', + ], + + 'clusters' => [ + 'default' => [ + [ + 'host' => env('REDIS_HOST', '127.0.0.1'), + 'password' => env('REDIS_PASSWORD', null), + 'port' => env('REDIS_PORT', 6379), + 'database' => 0, + ], + ], + ], + + ], + +### Routing + +#### Post Size Middleware + +The class `Illuminate\Foundation\Http\Middleware\VerifyPostSize` has been renamed to `Illuminate\Foundation\Http\Middleware\ValidatePostSize`. + +#### The `middleware` Method + +The `middleware` method of the `Illuminate\Routing\Router` class has been renamed to `aliasMiddleware()`. It is likely that most applications never call this method manually, as it is typically only called by the HTTP kernel to register route-level middleware defined in the `$routeMiddleware` array. + +#### The `getParameter` Method + +The `getParameter` method of the `Illuminate\Routing\Route` class has been removed. You should use the `parameter` method instead. + +### Sessions + +#### Symfony Compatibility + +Laravel's session handlers no longer implements Symfony's `SessionInterface`. Implementing this interface required us to implement extraneous features that were not needed by the framework. Instead, a new `Illuminate\Contracts\Session\Session` interface has been defined and may be used instead. The following code changes should also be applied: + +All calls to the `->set()` method should be changed to `->put()`. Typically, Laravel applications would never call the `set` method since it has never been documented within the Laravel documentation. However, it is included here out of caution. + +All calls to the `->getToken()` method should be changed to `->token()`. + +All calls to the `$request->setSession()` method should be changed to `setLaravelSession()`. + +### Testing + +Laravel 5.4's testing layer has been re-written to be simpler and lighter out of the box. If you would like to continue using the testing layer present in Laravel 5.3, you may install the `laravel/browser-kit-testing` [package](https://github.com/laravel/browser-kit-testing) into your application. This package provides full compatibility with the Laravel 5.3 testing layer. In fact, you can run the Laravel 5.4 testing layer side-by-side with the Laravel 5.3 testing layer. + +If you have tests written using Laravel 5.3 and would like to run them side-by-side with Laravel's new testing layer, install the `laravel/browser-kit-testing` package: + + composer require laravel/browser-kit-testing + +Next, create a copy of your `tests/TestCase.php` file and save it to your `tests` directory as `BrowserKitTest.php`. Then, modify the file to extend the `Laravel\BrowserKitTesting\TestCase` class. Once you have done this, you should have two base test classes in your `tests` directory: `TestCase.php` and `BrowserKitTest.php`. In order for your `BrowserKitTest` class to be properly loaded, you may need to add it to your `composer.json` file: + + "autoload-dev": { + "classmap": [ + "tests/TestCase.php", + "tests/BrowserKitTest.php" + ] + }, + +Tests written on Laravel 5.3 will extend the `BrowserKitTest` class while any new tests that use the Laravel 5.4 testing layer will extend the `TestCase` class. Your `BrowserKitTest` class should look like the following: + + make(Kernel::class)->bootstrap(); + + return $app; + } + } + +Once you have created this class, make sure to update all of your tests to extend your new `BrowserKitTest` class. This will allow all of your tests written on Laravel 5.3 to continue running on Laravel 5.4. If you choose, you can slowly begin to port them over to the new [Laravel 5.4 test syntax](/docs/5.4/http-tests) or [Laravel Dusk](/docs/5.4/dusk). + +> {note} If you are writing new tests and want them to use the Laravel 5.4 testing layer, make sure to extend the `TestCase` class. + +#### Installing Dusk In An Upgraded Application + +If you would like to install Laravel Dusk into an application that has been upgraded from Laravel 5.3, first install it via Composer: + + composer require laravel/dusk + +Next, you will need to create a `CreatesApplication` trait in your `tests` directory. This trait is responsible for creating fresh application instances for test cases. The trait should look like the following: + + make(Kernel::class)->bootstrap(); + + return $app; + } + } + +> {note} If you have namespaced your tests and are using the PSR-4 autoloading standard to load your `tests` directory, you should place the `CreatesApplication` trait under the appropriate namespace. + +Once you have completed these preparatory steps, you can follow the normal [Dusk installation instructions](/docs/{{version}}/dusk#installation). + +#### Environment + +The Laravel 5.4 test class no longer manually forces `putenv('APP_ENV=testing')` for each test. Instead, the framework utilizes the `APP_ENV` variable from the loaded `.env` file. + +#### Event Fake + +The `Event` fake's `assertFired` method should be updated to `assertDispatched`. The method signature has not been changed. + +#### Mail Fake + +The `Mail` fake has been greatly simplified for the Laravel 5.4 release. Instead of using the `assertSentTo` method, you should now simply use the `assertSent` method and utilize the `hasTo`, `hasCc`, etc. helper methods within your callback: + + Mail::assertSent(MailableName::class, function ($mailable) { + return $mailable->hasTo('email@example.com'); + }); + +### Translation + +#### `{Inf}` Placeholder + +If you are using the `{Inf}` placeholder for pluralizing your translation strings, you should update your translation strings to use the `*` character instead: + + {0} First Message|{1,*} Second Message + +### URL Generation + +#### The `forceSchema` Method + +The `forceSchema` method of the `Illuminate\Routing\UrlGenerator` class has been renamed to `forceScheme`. + +### Validation + +#### Date Format Validation + +Date format validation is now more strict and supports the placeholders present within the documentation for the PHP [date function](http://php.net/manual/en/function.date.php). In previous releases of Laravel, the timezone placeholder `P` would accept all timezone formats; however, in Laravel 5.4 each timezone format has a unique placeholder as per the PHP documentation. + +#### Method Names + +The `addError` method has been renamed to `addFailure`. In addition, the `doReplacements` method has been renamed to `makeReplacements`. Typically, these changes will only be relevant if you are extending the `Validator` class. + +### Miscellaneous + +We also encourage you to view the changes in the `laravel/laravel` [GitHub repository](https://github.com/laravel/laravel). While many of these changes are not required, you may wish to keep these files in sync with your application. Some of these changes will be covered in this upgrade guide, but others, such as changes to configuration files or comments, will not be. You can easily view the changes with the [Github comparison tool](https://github.com/laravel/laravel/compare/5.3...master) and choose which updates are important to you. diff --git a/valet.md b/valet.md new file mode 100644 index 0000000..73d9741 --- /dev/null +++ b/valet.md @@ -0,0 +1,232 @@ +# Laravel Valet + +- [Introduction](#introduction) + - [Valet Or Homestead](#valet-or-homestead) +- [Installation](#installation) + - [Upgrading](#upgrading) +- [Serving Sites](#serving-sites) + - [The "Park" Command](#the-park-command) + - [The "Link" Command](#the-link-command) + - [Securing Sites With TLS](#securing-sites) +- [Sharing Sites](#sharing-sites) +- [Custom Valet Drivers](#custom-valet-drivers) +- [Other Valet Commands](#other-valet-commands) + + +## Introduction + +Valet is a Laravel development environment for Mac minimalists. No Vagrant, no `/etc/hosts` file. You can even share your sites publicly using local tunnels. _Yeah, we like it too._ + +Laravel Valet configures your Mac to always run [Nginx](https://www.nginx.com/) in the background when your machine starts. Then, using [DnsMasq](https://en.wikipedia.org/wiki/Dnsmasq), Valet proxies all requests on the `*.dev` domain to point to sites installed on your local machine. + +In other words, a blazing fast Laravel development environment that uses roughly 7 MB of RAM. Valet isn't a complete replacement for Vagrant or Homestead, but provides a great alternative if you want flexible basics, prefer extreme speed, or are working on a machine with a limited amount of RAM. + +Out of the box, Valet support includes, but is not limited to: + +
    +- [Laravel](https://laravel.com) +- [Lumen](https://lumen.laravel.com) +- [Symfony](https://symfony.com) +- [Zend](https://framework.zend.com) +- [CakePHP 3](https://cakephp.org) +- [WordPress](https://wordpress.org) +- [Bedrock](https://roots.io/bedrock/) +- [Craft](https://craftcms.com) +- [Statamic](https://statamic.com) +- [Jigsaw](http://jigsaw.tighten.co) +- Static HTML +
    + +However, you may extend Valet with your own [custom drivers](#custom-valet-drivers). + + +### Valet Or Homestead + +As you may know, Laravel offers [Homestead](/docs/{{version}}/homestead), another local Laravel development environment. Homestead and Valet differ in regards to their intended audience and their approach to local development. Homestead offers an entire Ubuntu virtual machine with automated Nginx configuration. Homestead is a wonderful choice if you want a fully virtualized Linux development environment or are on Windows / Linux. + +Valet only supports Mac, and requires you to install PHP and a database server directly onto your local machine. This is easily achieved by using [Homebrew](http://brew.sh/) with commands like `brew install php71` and `brew install mysql`. Valet provides a blazing fast local development environment with minimal resource consumption, so it's great for developers who only require PHP / MySQL and do not need a fully virtualized development environment. + +Both Valet and Homestead are great choices for configuring your Laravel development environment. Which one you choose will depend on your personal taste and your team's needs. + + +## Installation + +**Valet requires macOS and [Homebrew](http://brew.sh/). Before installation, you should make sure that no other programs such as Apache or Nginx are binding to your local machine's port 80.** + +
    +- Install or update [Homebrew](http://brew.sh/) to the latest version using `brew update`. +- Install PHP 7.1 using Homebrew via `brew install homebrew/php/php71`. +- Install Valet with Composer via `composer global require laravel/valet`. Make sure the `~/.composer/vendor/bin` directory is in your system's "PATH". +- Run the `valet install` command. This will configure and install Valet and DnsMasq, and register Valet's daemon to launch when your system starts. +
    + +Once Valet is installed, try pinging any `*.dev` domain on your terminal using a command such as `ping foobar.dev`. If Valet is installed correctly you should see this domain responding on `127.0.0.1`. + +Valet will automatically start its daemon each time your machine boots. There is no need to run `valet start` or `valet install` ever again once the initial Valet installation is complete. + +#### Using Another Domain + +By default, Valet serves your projects using the `.dev` TLD. If you'd like to use another domain, you can do so using the `valet domain tld-name` command. + +For example, if you'd like to use `.app` instead of `.dev`, run `valet domain app` and Valet will start serving your projects at `*.app` automatically. + +#### Database + +If you need a database, try MySQL by running `brew install mysql` on your command line. Once MySQL has been installed, you may start it using the `brew services start mysql` command. You can then connect to the database at `127.0.0.1` using the `root` username and an empty string for the password. + + +### Upgrading + +You may update your Valet installation using the `composer global update` command in your terminal. After upgrading, it is good practice to run the `valet install` command so Valet can make additional upgrades to your configuration files if necessary. + +#### Upgrading To Valet 2.0 + +Valet 2.0 transitions Valet's underlying web server from Caddy to Nginx. Before upgrading to this version you should run the following commands to stop and uninstall the existing Caddy daemon: + + valet stop + valet uninstall + +Next, you should upgrade to the latest version of Valet. Depending on how you installed Valet, this is typically done through Git or Composer. If you installed Valet via Composer, you should use the following command to update to the latest major version: + + composer global require laravel/valet + +Once the fresh Valet source code has been downloaded, you should run the `install` command: + + valet install + valet restart + +After upgrading, it may be necessary to re-park or re-link your sites. + + +## Serving Sites + +Once Valet is installed, you're ready to start serving sites. Valet provides two commands to help you serve your Laravel sites: `park` and `link`. + + +**The `park` Command** + +
    +- Create a new directory on your Mac by running something like `mkdir ~/Sites`. Next, `cd ~/Sites` and run `valet park`. This command will register your current working directory as a path that Valet should search for sites. +- Next, create a new Laravel site within this directory: `laravel new blog`. +- Open `http://blog.dev` in your browser. +
    + +**That's all there is to it.** Now, any Laravel project you create within your "parked" directory will automatically be served using the `http://folder-name.dev` convention. + + +**The `link` Command** + +The `link` command may also be used to serve your Laravel sites. This command is useful if you want to serve a single site in a directory and not the entire directory. + +
    +- To use the command, navigate to one of your projects and run `valet link app-name` in your terminal. Valet will create a symbolic link in `~/.valet/Sites` which points to your current working directory. +- After running the `link` command, you can access the site in your browser at `http://app-name.dev`. +
    + +To see a listing of all of your linked directories, run the `valet links` command. You may use `valet unlink app-name` to destroy the symbolic link. + +> {tip} You can use `valet link` to serve the same project from multiple (sub)domains. To add a subdomain or another domain to your project run `valet link subdomain.app-name` from the project folder. + + +**Securing Sites With TLS** + +By default, Valet serves sites over plain HTTP. However, if you would like to serve a site over encrypted TLS using HTTP/2, use the `secure` command. For example, if your site is being served by Valet on the `laravel.dev` domain, you should run the following command to secure it: + + valet secure laravel + +To "unsecure" a site and revert back to serving its traffic over plain HTTP, use the `unsecure` command. Like the `secure` command, this command accepts the host name that you wish to unsecure: + + valet unsecure laravel + + +## Sharing Sites + +Valet even includes a command to share your local sites with the world. No additional software installation is required once Valet is installed. + +To share a site, navigate to the site's directory in your terminal and run the `valet share` command. A publicly accessible URL will be inserted into your clipboard and is ready to paste directly into your browser. That's it. + +To stop sharing your site, hit `Control + C` to cancel the process. + +> {note} `valet share` does not currently support sharing sites that have been secured using the `valet secure` command. + + +## Custom Valet Drivers + +You can write your own Valet "driver" to serve PHP applications running on another framework or CMS that is not natively supported by Valet. When you install Valet, a `~/.valet/Drivers` directory is created which contains a `SampleValetDriver.php` file. This file contains a sample driver implementation to demonstrate how to write a custom driver. Writing a driver only requires you to implement three methods: `serves`, `isStaticFile`, and `frontControllerPath`. + +All three methods receive the `$sitePath`, `$siteName`, and `$uri` values as their arguments. The `$sitePath` is the fully qualified path to the site being served on your machine, such as `/Users/Lisa/Sites/my-project`. The `$siteName` is the "host" / "site name" portion of the domain (`my-project`). The `$uri` is the incoming request URI (`/foo/bar`). + +Once you have completed your custom Valet driver, place it in the `~/.valet/Drivers` directory using the `FrameworkValetDriver.php` naming convention. For example, if you are writing a custom valet driver for WordPress, your file name should be `WordPressValetDriver.php`. + +Let's take a look at a sample implementation of each method your custom Valet driver should implement. + +#### The `serves` Method + +The `serves` method should return `true` if your driver should handle the incoming request. Otherwise, the method should return `false`. So, within this method you should attempt to determine if the given `$sitePath` contains a project of the type you are trying to serve. + +For example, let's pretend we are writing a `WordPressValetDriver`. Our serve method might look something like this: + + /** + * Determine if the driver serves the request. + * + * @param string $sitePath + * @param string $siteName + * @param string $uri + * @return bool + */ + public function serves($sitePath, $siteName, $uri) + { + return is_dir($sitePath.'/wp-admin'); + } + +#### The `isStaticFile` Method + +The `isStaticFile` should determine if the incoming request is for a file that is "static", such as an image or a stylesheet. If the file is static, the method should return the fully qualified path to the static file on disk. If the incoming request is not for a static file, the method should return `false`: + + /** + * Determine if the incoming request is for a static file. + * + * @param string $sitePath + * @param string $siteName + * @param string $uri + * @return string|false + */ + public function isStaticFile($sitePath, $siteName, $uri) + { + if (file_exists($staticFilePath = $sitePath.'/public/'.$uri)) { + return $staticFilePath; + } + + return false; + } + +> {note} The `isStaticFile` method will only be called if the `serves` method returns `true` for the incoming request and the request URI is not `/`. + +#### The `frontControllerPath` Method + +The `frontControllerPath` method should return the fully qualified path to your application's "front controller", which is typically your "index.php" file or equivalent: + + /** + * Get the fully resolved path to the application's front controller. + * + * @param string $sitePath + * @param string $siteName + * @param string $uri + * @return string + */ + public function frontControllerPath($sitePath, $siteName, $uri) + { + return $sitePath.'/public/index.php'; + } + + +## Other Valet Commands + +Command | Description +------------- | ------------- +`valet forget` | Run this command from a "parked" directory to remove it from the parked directory list. +`valet paths` | View all of your "parked" paths. +`valet restart` | Restart the Valet daemon. +`valet start` | Start the Valet daemon. +`valet stop` | Stop the Valet daemon. +`valet uninstall` | Uninstall the Valet daemon entirely. diff --git a/validation.md b/validation.md old mode 100755 new mode 100644 index 8037945..d4fd973 --- a/validation.md +++ b/validation.md @@ -1,282 +1,691 @@ -# စိစစ်ခြင်း - -- [အခြေခံအသုံးပြုပုံ](#basic-usage) +# Validation + +- [Introduction](#introduction) +- [Validation Quickstart](#validation-quickstart) + - [Defining The Routes](#quick-defining-the-routes) + - [Creating The Controller](#quick-creating-the-controller) + - [Writing The Validation Logic](#quick-writing-the-validation-logic) + - [Displaying The Validation Errors](#quick-displaying-the-validation-errors) +- [Form Request Validation](#form-request-validation) + - [Creating Form Requests](#creating-form-requests) + - [Authorizing Form Requests](#authorizing-form-requests) + - [Customizing The Error Format](#customizing-the-error-format) + - [Customizing The Error Messages](#customizing-the-error-messages) +- [Manually Creating Validators](#manually-creating-validators) + - [Automatic Redirection](#automatic-redirection) + - [Named Error Bags](#named-error-bags) + - [After Validation Hook](#after-validation-hook) - [Working With Error Messages](#working-with-error-messages) -- [Error Messages & Views](#error-messages-and-views) + - [Custom Error Messages](#custom-error-messages) - [Available Validation Rules](#available-validation-rules) - [Conditionally Adding Rules](#conditionally-adding-rules) -- [Custom Error Messages](#custom-error-messages) +- [Validating Arrays](#validating-arrays) - [Custom Validation Rules](#custom-validation-rules) - -## အခြေခံအသုံးပြုပုံ + +## Introduction + +Laravel provides several different approaches to validate your application's incoming data. By default, Laravel's base controller class uses a `ValidatesRequests` trait which provides a convenient method to validate incoming HTTP request with a variety of powerful validation rules. + + +## Validation Quickstart + +To learn about Laravel's powerful validation features, let's look at a complete example of validating a form and displaying the error messages back to the user. + + +### Defining The Routes + +First, let's assume we have the following routes defined in our `routes/web.php` file: + + Route::get('post/create', 'PostController@create'); + + Route::post('post', 'PostController@store'); + +Of course, the `GET` route will display a form for the user to create a new blog post, while the `POST` route will store the new blog post in the database. + + +### Creating The Controller + +Next, let's take a look at a simple controller that handles these routes. We'll leave the `store` method empty for now: + + +### Writing The Validation Logic + +Now we are ready to fill in our `store` method with the logic to validate the new blog post. If you examine your application's base controller (`App\Http\Controllers\Controller`) class, you will see that the class uses a `ValidatesRequests` trait. This trait provides a convenient `validate` method to all of your controllers. + +The `validate` method accepts an incoming HTTP request and a set of validation rules. If the validation rules pass, your code will keep executing normally; however, if validation fails, an exception will be thrown and the proper error response will automatically be sent back to the user. In the case of a traditional HTTP request, a redirect response will be generated, while a JSON response will be sent for AJAX requests. + +To get a better understanding of the `validate` method, let's jump back into the `store` method: + + /** + * Store a new blog post. + * + * @param Request $request + * @return Response + */ + public function store(Request $request) + { + $this->validate($request, [ + 'title' => 'required|unique:posts|max:255', + 'body' => 'required', + ]); + + // The blog post is valid, store in database... + } + +As you can see, we simply pass the incoming HTTP request and desired validation rules into the `validate` method. Again, if the validation fails, the proper response will automatically be generated. If the validation passes, our controller will continue executing normally. + +#### Stopping On First Validation Failure + +Sometimes you may wish to stop running validation rules on an attribute after the first validation failure. To do so, assign the `bail` rule to the attribute: + + $this->validate($request, [ + 'title' => 'bail|required|unique:posts|max:255', + 'body' => 'required', + ]); + +In this example, if the `required` rule on the `title` attribute fails, the `unique` rule will not be checked. Rules will be validated in the order they are assigned. + +#### A Note On Nested Attributes + +If your HTTP request contains "nested" parameters, you may specify them in your validation rules using "dot" syntax: + + $this->validate($request, [ + 'title' => 'required|unique:posts|max:255', + 'author.name' => 'required', + 'author.description' => 'required', + ]); + + +### Displaying The Validation Errors + +So, what if the incoming request parameters do not pass the given validation rules? As mentioned previously, Laravel will automatically redirect the user back to their previous location. In addition, all of the validation errors will automatically be [flashed to the session](/docs/{{version}}/session#flash-data). + +Again, notice that we did not have to explicitly bind the error messages to the view in our `GET` route. This is because Laravel will check for errors in the session data, and automatically bind them to the view if they are available. The `$errors` variable will be an instance of `Illuminate\Support\MessageBag`. For more information on working with this object, [check out its documentation](#working-with-error-messages). + +> {tip} The `$errors` variable is bound to the view by the `Illuminate\View\Middleware\ShareErrorsFromSession` middleware, which is provided by the `web` middleware group. **When this middleware is applied an `$errors` variable will always be available in your views**, allowing you to conveniently assume the `$errors` variable is always defined and can be safely used. + +So, in our example, the user will be redirected to our controller's `create` method when validation fails, allowing us to display the error messages in the view: + + + +

    Create Post

    -Laravel အနေဖြင့် data များကို စိစစ်ရာတွင် ရိုးရှင်း အဆင်ပြေသော နည်းလမ်းများကို အသုံးပြုထားသည်။ error message များကို `Validation` class မှ တဆင့် ထုတ်ယူနိုင်သည်။ + @if (count($errors) > 0) +
    +
      + @foreach ($errors->all() as $error) +
    • {{ $error }}
    • + @endforeach +
    +
    + @endif -#### အခြေခံအသုံးပြုပုံ ဥပမာ + + + +#### Customizing The Flashed Error Format + +If you wish to customize the format of the validation errors that are flashed to the session when validation fails, override the `formatValidationErrors` on your base controller. Don't forget to import the `Illuminate\Contracts\Validation\Validator` class at the top of the file: + + 'Dayle'), - array('name' => 'required|min:5') - ); + use Illuminate\Foundation\Bus\DispatchesJobs; + use Illuminate\Contracts\Validation\Validator; + use Illuminate\Routing\Controller as BaseController; + use Illuminate\Foundation\Validation\ValidatesRequests; -Validation ပြုလုပ်ရာတွင် `make` method ဟုသည့် method ကို အသုံးပြုပြီး array တွင်းပါရှိမည့် ပထမ argument မှာ data ဖြစ်ပြီး ဒုတိယ argument မှာ ထို data များကို စိစစ်မည့် rule များကို ထည့်သွင်းရမည်။ + abstract class Controller extends BaseController + { + use DispatchesJobs, ValidatesRequests; + /** + * {@inheritdoc} + */ + protected function formatValidationErrors(Validator $validator) + { + return $validator->errors()->all(); + } + } -#### Array ကို အသုံးပြု၍ Rule များ သတ်မှတ်ခြင်း + +#### AJAX Requests & Validation -တခုထက်ပိုသော rule များကို သတ်မှတ်လိုပါက "pipe" character ကိုဖြစ်စေ array အတွင်း ခြား၍ဖြစ်စေ ထည့်သွင်းနိုင်သည်။ +In this example, we used a traditional form to send data to the application. However, many applications use AJAX requests. When using the `validate` method during an AJAX request, Laravel will not generate a redirect response. Instead, Laravel generates a JSON response containing all of the validation errors. This JSON response will be sent with a 422 HTTP status code. - $validator = Validator::make( - array('name' => 'Dayle'), - array('name' => array('required', 'min:5')) - ); + +## Form Request Validation -#### Fields များစွာကို စိစစ်ခြင်း + +### Creating Form Requests - $validator = Validator::make( - array( - 'name' => 'Dayle', - 'password' => 'lamepassword', - 'email' => 'email@example.com' - ), - array( - 'name' => 'required', - 'password' => 'required|min:8', - 'email' => 'required|email|unique:users' - ) - ); +For more complex validation scenarios, you may wish to create a "form request". Form requests are custom request classes that contain validation logic. To create a form request class, use the `make:request` Artisan CLI command: -`Validator` instance ကို ပြုလုပ်ပြီးပါက `fails` သို ့မဟုတ် `passes` method ကို အသုံးပြု၍ အချက်အလက်များ စိစစ်နိုင်သည်။ + php artisan make:request StoreBlogPost +The generated class will be placed in the `app/Http/Requests` directory. If this directory does not exist, it will be created when you run the `make:request` command. Let's add a few validation rules to the `rules` method: - if ($validator->fails()) - { - // The given data did not pass validation - } + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + 'title' => 'required|unique:posts|max:255', + 'body' => 'required', + ]; + } -စိစစ်ခြင်း မအောင်မြင်ပါက validator မှ error message ကို ရယူနိုင်ပေသည်။ +So, how are the validation rules evaluated? All you need to do is type-hint the request on your controller method. The incoming form request is validated before the controller method is called, meaning you do not need to clutter your controller with any validation logic: - $messages = $validator->messages(); + /** + * Store the incoming blog post. + * + * @param StoreBlogPost $request + * @return Response + */ + public function store(StoreBlogPost $request) + { + // The incoming request is valid... + } -်fail ဖြစ်သည့် rule များကိုသာ ရယူလိုပြီး message များ မပါဝင်စေလိုပါက `failed` method ကို အသုံးပြုနိုင်သည်။ +If validation fails, a redirect response will be generated to send the user back to their previous location. The errors will also be flashed to the session so they are available for display. If the request was an AJAX request, a HTTP response with a 422 status code will be returned to the user including a JSON representation of the validation errors. - $failed = $validator->failed(); +#### Adding After Hooks To Form Requests -#### Files များစိစစ်ခြင်း +If you would like to add an "after" hook to a form request, you may use the `withValidator` method. This method receives the fully constructed validator, allowing you to call any of its methods before the validation rules are actually evaluated: -`Validator` class အနေဖြင့် `size` နှင့် `mimes` အပါအဝင် များမြောင်လှသော validation method များကို အထောက်အပံ့ပေးထားပြီး file များ validate ပြုလုပ်လိုပါက ထိုထဲ့သို ့ ထည့်သွင်းရန်သာ လိုပေမည်။ + /** + * Configure the validator instance. + * + * @param \Illuminate\Validation\Validator $validator + * @return void + */ + public function withValidator($validator) + { + $validator->after(function ($validator) { + if ($this->somethingElseIsInvalid()) { + $validator->errors()->add('field', 'Something is wrong with this field!'); + } + }); + } + + +### Authorizing Form Requests + +The form request class also contains an `authorize` method. Within this method, you may check if the authenticated user actually has the authority to update a given resource. For example, you may determine if a user actually owns a blog comment they are attempting to update: + + /** + * Determine if the user is authorized to make this request. + * + * @return bool + */ + public function authorize() + { + $comment = Comment::find($this->route('comment')); + + return $comment && $this->user()->can('update', $comment); + } + +Since all form requests extend the base Laravel request class, we may use the `user` method to access the currently authenticated user. Also note the call to the `route` method in the example above. This method grants you access to the URI parameters defined on the route being called, such as the `{comment}` parameter in the example below: + + Route::post('comment/{comment}'); + +If the `authorize` method returns `false`, a HTTP response with a 403 status code will automatically be returned and your controller method will not execute. + +If you plan to have authorization logic in another part of your application, simply return `true` from the `authorize` method: + + /** + * Determine if the user is authorized to make this request. + * + * @return bool + */ + public function authorize() + { + return true; + } + +### Customizing The Error Format + +If you wish to customize the format of the validation errors that are flashed to the session when validation fails, override the `formatErrors` on your base request (`App\Http\Requests\Request`). Don't forget to import the `Illuminate\Contracts\Validation\Validator` class at the top of the file: + + /** + * {@inheritdoc} + */ + protected function formatErrors(Validator $validator) + { + return $validator->errors()->all(); + } + + +### Customizing The Error Messages + +You may customize the error messages used by the form request by overriding the `messages` method. This method should return an array of attribute / rule pairs and their corresponding error messages: + + /** + * Get the error messages for the defined validation rules. + * + * @return array + */ + public function messages() + { + return [ + 'title.required' => 'A title is required', + 'body.required' => 'A message is required', + ]; + } + + +## Manually Creating Validators + +If you do not want to use the `ValidatesRequests` trait's `validate` method, you may create a validator instance manually using the `Validator` [facade](/docs/{{version}}/facades). The `make` method on the facade generates a new validator instance: + + all(), [ + 'title' => 'required|unique:posts|max:255', + 'body' => 'required', + ]); + + if ($validator->fails()) { + return redirect('post/create') + ->withErrors($validator) + ->withInput(); + } + + // Store the blog post... + } + } + +The first argument passed to the `make` method is the data under validation. The second argument is the validation rules that should be applied to the data. + +After checking if the request validation failed, you may use the `withErrors` method to flash the error messages to the session. When using this method, the `$errors` variable will automatically be shared with your views after redirection, allowing you to easily display them back to the user. The `withErrors` method accepts a validator, a `MessageBag`, or a PHP `array`. + + +### Automatic Redirection + +If you would like to create a validator instance manually but still take advantage of the automatic redirection offered by the `ValidatesRequest` trait, you may call the `validate` method on an existing validator instance. If validation fails, the user will automatically be redirected or, in the case of an AJAX request, a JSON response will be returned: + + Validator::make($request->all(), [ + 'title' => 'required|unique:posts|max:255', + 'body' => 'required', + ])->validate(); + + +### Named Error Bags + +If you have multiple forms on a single page, you may wish to name the `MessageBag` of errors, allowing you to retrieve the error messages for a specific form. Simply pass a name as the second argument to `withErrors`: + + return redirect('register') + ->withErrors($validator, 'login'); + +You may then access the named `MessageBag` instance from the `$errors` variable: + + {{ $errors->login->first('email') }} + + +### After Validation Hook + +The validator also allows you to attach callbacks to be run after validation is completed. This allows you to easily perform further validation and even add more error messages to the message collection. To get started, use the `after` method on a validator instance: + + $validator = Validator::make(...); + + $validator->after(function ($validator) { + if ($this->somethingElseIsInvalid()) { + $validator->errors()->add('field', 'Something is wrong with this field!'); + } + }); + + if ($validator->fails()) { + // + } -## Error Messages များနှင့် လှုပ်ရှားခြင်း +## Working With Error Messages +After calling the `errors` method on a `Validator` instance, you will receive an `Illuminate\Support\MessageBag` instance, which has a variety of convenient methods for working with error messages. The `$errors` variable that is automatically made available to all views is also an instance of the `MessageBag` class. -After calling the on a -`Validator` instance မှ `messages` method ကို ခေါ်ပြီးပါက Error message များဖြင့် အလုပ်လုပ်ရာတွင် လွယ်ကူစေမည့် method များစွာပါဝင်မည့် `MessageBag` ပါဝင်မည် ဖြစ်သည်။ +#### Retrieving The First Error Message For A Field -#### Field တစ်ခုမှ ပထမဆုံး Error Message ကို ထုတ်ယူခြင်း +To retrieve the first error message for a given field, use the `first` method: - echo $messages->first('email'); + $errors = $validator->errors(); -#### Field တစ်ခုမှ Error Message များထုတ်ယူခြင်း + echo $errors->first('email'); - foreach ($messages->get('email') as $message) - { - // - } +#### Retrieving All Error Messages For A Field -#### Field အားလုံးမှ Error Message များထုတ်ယူခြင်း +If you need to retrieve an array of all the messages for a given field, use the `get` method: - foreach ($messages->all() as $message) - { - // - } + foreach ($errors->get('email') as $message) { + // + } -#### Field တစ်ခုမှ message ရှိမရှိ စစ်ဆေးခြင်း +If you are validating an array form field, you may retrieve all of the messages for each of the array elements using the `*` character: - if ($messages->has('email')) - { - // - } + foreach ($errors->get('attachments.*') as $message) { + // + } -#### Error Message များအား Format ပြောင်း၍ ထုတ်ယူခြင်း +#### Retrieving All Error Messages For All Fields - echo $messages->first('email', '

    :message

    '); - -> **မှတ်ချက်:** ပုံမှန်အားဖြင့် messages များကို Bootstrap ဖြင့် အဆင်ပြေမည့် ပုံစံများအနေဖြင့် သတ်မှတ်ထားပါသည်။ +To retrieve an array of all messages for all fields, use the `all` method: -#### Error Messages များအား Format တစ်ခု သတ်မှတ်၍ ထုတ်ယူခြင်း + foreach ($errors->all() as $message) { + // + } - foreach ($messages->all('
  • :message
  • ') as $message) - { - // - } +#### Determining If Messages Exist For A Field - -## Error Message များနှင့် View များ +The `has` method may be used to determine if any error messages exist for a given field: -Validation ကို ဆောင်ရွက်ပြီးသည်နှင့် Error message များကို လွယ်လင့်တကူ ပြန်လည်ပြသနိုင်ရန် လိုအပ်ပေသည်။ ထိုလိုအပ်ချက်များကို Laravel မှ အဆင်ပြေလွယ်ကူစွာ ဖြည့်စွမ်းထားသည်။ အောက်ပါ route များကို ဥပမာ အနေဖြင့်ကြည့်ပါ။ + if ($errors->has('email')) { + // + } - Route::get('register', function() - { - return View::make('user.register'); - }); + +### Custom Error Messages - Route::post('register', function() - { - $rules = array(...); +If needed, you may use custom error messages for validation instead of the defaults. There are several ways to specify custom messages. First, you may pass the custom messages as the third argument to the `Validator::make` method: - $validator = Validator::make(Input::all(), $rules); + $messages = [ + 'required' => 'The :attribute field is required.', + ]; - if ($validator->fails()) - { - return Redirect::to('register')->withErrors($validator); - } - }); + $validator = Validator::make($input, $rules, $messages); - -Note that when စိစစ်ခြင်း မအောင်မြင်ပါက `Validator` instance ကို `withErrors` method ဖြင့် Error များကို passing ပေးလိုက်ပြီး Redirect ပြုလုပ်လိုက်သည် ကို တွေ ့ရပေမည်။ အဆိုပါ method ကို အသုံးပြုခြင်းဖြင့် error message များကို လွယ်လင့်တကူ ဖြတ်ကနဲ ပြသရာတွင် သုံးနိုင်ရင် next request ၏ Session ထဲတွင် ထည့်သွင်းထားပါသည်။ +In this example, the `:attribute` place-holder will be replaced by the actual name of the field under validation. You may also utilize other place-holders in validation messages. For example: -သို ့ပင်သော်ညား GET route နဲ ့ Error Message များကို အသေချည်နှောင်ထားရန် မလိုသည်ကို သတိပြုရမည်။ အဘယ်ကြောင့်ဆိုသော် Laravel သည် Session data များမှ Error များကို စစ်ဆေးပြီး view ဆီသို ့ အဆင်ပြေသည်နှင့် တပြိုင်နက် ပြသနိုင်ရန် ပြင်ဆင်ထားသည်ကို သတိပြုရမည်။ **ထိုကြောင့် အရေးကြီးသည့် အချက်မှာ`$errors` ဟုသည် variable မှာ သင့် view ၏ request တိုင်းတွင် ပြင်ဆင်ထားသောကြောင့် အမြဲတမ်း အဆင်သင့် ဖြစ်နေသည်ကို မှတ်ထားရန်လိုသည်။ `$errors` variable မှာ `MessageBag` ၏ instance ဖြစ်သည်။ + $messages = [ + 'same' => 'The :attribute and :other must match.', + 'size' => 'The :attribute must be exactly :size.', + 'between' => 'The :attribute must be between :min - :max.', + 'in' => 'The :attribute must be one of the following types: :values', + ]; -ထိုကြောင့် redirect ပြုလုပ်ပြီးနောက် `$errors` variable နှင့် သင့် view မှာ အလိုအလျောက် ချည်နှောင်ပြီးသား ဖြစ်ပေသည်။ +#### Specifying A Custom Message For A Given Attribute + +Sometimes you may wish to specify a custom error messages only for a specific field. You may do so using "dot" notation. Specify the attribute's name first, followed by the rule: - first('email'); ?> + $messages = [ + 'email.required' => 'We need to know your e-mail address!', + ]; + + +#### Specifying Custom Messages In Language Files -### အမည်ပေးထားသော Error Bag များ +In most cases, you will probably specify your custom messages in a language file instead of passing them directly to the `Validator`. To do so, add your messages to `custom` array in the `resources/lang/xx/validation.php` language file. -သင့်အနေဖြင့် Page တစ်ခုတည်းတွင် များပြားလှသော form များသည်ရှိသည် ဆိုပါစို ့။ ထိုအခါ သင့်အနေဖြင့် Error များ၏ `MessageBag` များကို ကွဲပြားခြားနား စေရန် အမည်နာမ ပေးလိုပေမည်။ ထိုအခါတွင် သင့်အနေဖြင့် `withErrors` ဟုသည့် method ၏ ဒုတိယ argument အနေဖြင့် မိမိပေးလိုသည့် အမည်ကို ထည့်သွင်းနိုင်သည်။ + 'custom' => [ + 'email' => [ + 'required' => 'We need to know your e-mail address!', + ], + ], - return Redirect::to('register')->withErrors($validator, 'login'); +#### Specifying Custom Attributes In Language Files -ထိုနောက် သင့်အနေဖြင့် `$errors` variable မှ `MessageBag` instance ကို အောက်ပါအတိုင်း ဆွဲထုတ်နိုင်သည်။ +If you would like the `:attribute` portion of your validation message to be replaced with a custom attribute name, you may specify the custom name in the `attributes` array of your `resources/lang/xx/validation.php` language file: - login->first('email'); ?> + 'attributes' => [ + 'email' => 'email address', + ], -## အသုံးပြုနိုင်သည့် စိစစ်ခြင်း Rule များ - -အောက်တွင် ဖော်ပြထားသည်မှာ အသုံးပြုနိုင်သော စိစစ်ရေး rule များနှင့် ၄င်းတို ့၏ function များဖြစ်ကြသည်။ - -- [Accepted](#rule-accepted) -- [Active URL](#rule-active-url) -- [After (Date)](#rule-after) -- [Alpha](#rule-alpha) -- [Alpha Dash](#rule-alpha-dash) -- [Alpha Numeric](#rule-alpha-num) -- [Array](#rule-array) -- [Before (Date)](#rule-before) -- [Between](#rule-between) -- [Confirmed](#rule-confirmed) -- [Date](#rule-date) -- [Date Format](#rule-date-format) -- [Different](#rule-different) -- [Digits](#rule-digits) -- [Digits Between](#rule-digits-between) -- [E-Mail](#rule-email) -- [Exists (Database)](#rule-exists) -- [Image (File)](#rule-image) -- [In](#rule-in) -- [Integer](#rule-integer) -- [IP Address](#rule-ip) -- [Max](#rule-max) -- [MIME Types](#rule-mimes) -- [Min](#rule-min) -- [Not In](#rule-not-in) -- [Numeric](#rule-numeric) -- [Regular Expression](#rule-regex) -- [Required](#rule-required) -- [Required If](#rule-required-if) -- [Required With](#rule-required-with) -- [Required With All](#rule-required-with-all) -- [Required Without](#rule-required-without) -- [Required Without All](#rule-required-without-all) -- [Same](#rule-same) -- [Size](#rule-size) -- [Unique (Database)](#rule-unique) -- [URL](#rule-url) +## Available Validation Rules + +Below is a list of all available validation rules and their function: + + + +
    + +[Accepted](#rule-accepted) +[Active URL](#rule-active-url) +[After (Date)](#rule-after) +[After Or Equal (Date)](#rule-after-or-equal) +[Alpha](#rule-alpha) +[Alpha Dash](#rule-alpha-dash) +[Alpha Numeric](#rule-alpha-num) +[Array](#rule-array) +[Before (Date)](#rule-before) +[Before Or Equal (Date)](#rule-before-or-equal) +[Between](#rule-between) +[Boolean](#rule-boolean) +[Confirmed](#rule-confirmed) +[Date](#rule-date) +[Date Format](#rule-date-format) +[Different](#rule-different) +[Digits](#rule-digits) +[Digits Between](#rule-digits-between) +[Dimensions (Image Files)](#rule-dimensions) +[Distinct](#rule-distinct) +[E-Mail](#rule-email) +[Exists (Database)](#rule-exists) +[File](#rule-file) +[Filled](#rule-filled) +[Image (File)](#rule-image) +[In](#rule-in) +[In Array](#rule-in-array) +[Integer](#rule-integer) +[IP Address](#rule-ip) +[JSON](#rule-json) +[Max](#rule-max) +[MIME Types](#rule-mimetypes) +[MIME Type By File Extension](#rule-mimes) +[Min](#rule-min) +[Nullable](#rule-nullable) +[Not In](#rule-not-in) +[Numeric](#rule-numeric) +[Present](#rule-present) +[Regular Expression](#rule-regex) +[Required](#rule-required) +[Required If](#rule-required-if) +[Required Unless](#rule-required-unless) +[Required With](#rule-required-with) +[Required With All](#rule-required-with-all) +[Required Without](#rule-required-without) +[Required Without All](#rule-required-without-all) +[Same](#rule-same) +[Size](#rule-size) +[String](#rule-string) +[Timezone](#rule-timezone) +[Unique (Database)](#rule-unique) +[URL](#rule-url) + +
    #### accepted -အဆိုပါ field တွင် စိစစ်သည်မှာ _yes_, _on_, သို ့မဟုတ် _1_ တို ့ဖြစ်သည်။ "Terms of Service" ကဲ့သို ့ တခုသာ ရွေးမရွေး စိစစ်ရာနေရာများတွင် ၄င်းကို အသုံးပြုနိုင်သည်။ - +The field under validation must be _yes_, _on_, _1_, or _true_. This is useful for validating "Terms of Service" acceptance. #### active_url -အဆိုပါ field တွင် စိစစ်သည်မှာ `checkdnsrr` ဟုသည် PHP function ကို အသုံးပြု၍ အင်ထုထားသည့် URL ဟုတ်မဟုတ်ကို စစ်ဆေးသွားမည် ဖြစ်သည်။ +The field under validation must have a valid A or AAAA record according to the `dns_get_record` PHP function. #### after:_date_ -အဆိုပါ field တွင် စိစစ်သည်မှာ သတ်မှတ်ထားသော date အတွင်းတွင်သာ ထည့်သွင်းစေရန် ဖြစ်သည်။ date များကို PHP ၏ `strtotime` function ကို အသုံးပြု၍ ပြောင်းလဲကာ စိစစ်သွားမည် ဖြစ်သည်။ +The field under validation must be a value after a given date. The dates will be passed into the `strtotime` PHP function: + + 'start_date' => 'required|date|after:tomorrow' + +Instead of passing a date string to be evaluated by `strtotime`, you may specify another field to compare against the date: + + 'finish_date' => 'required|date|after:start_date' + + +#### after\_or\_equal:_date_ + +The field under validation must be a value after or equal to the given date. For more information, see the [after](#rule-after) rule. #### alpha -အဆိုပါ field တွင် ပါဝင်သော အချက်အလက်များသည် အက္ခရာ များသာ ဖြစ်ရမည် ဖြစ်သည်။ ဥပမာ ကိန်းဂဏန်းများကို လက်ခံသွားမည် မဟုတ်။ + +The field under validation must be entirely alphabetic characters. #### alpha_dash -အဆိုပါ field တွင် ပါဝင်သော အချက်အလက်များသည် အက္ခရာ နှင့် ကိန်းဂဏန်းများသာ မက dash နှင့် underscore ကိုပါ လက်ခံသွားမည် ဖြစ်သည်။ +The field under validation may have alpha-numeric characters, as well as dashes and underscores. #### alpha_num -အဆိုပါ field တွင် ပါဝင်သော အချက်အလက်များသည် အက္ခရာ နှင့် ကိန်းဂဏန်းများသာ လက်ခံသွားမည်။ +The field under validation must be entirely alpha-numeric characters. #### array -အဆိုပါ field တွင် ပါဝင်သော အချက်အလက်များသည် array အမျိုးအစားကိုသာ လက်ခံသွားမည်။ +The field under validation must be a PHP `array`. #### before:_date_ -အဆိုပါ field တွင်ပါဝင်သော အချက်အလက်များကို date ဖြင့် စိစစ်သတ်မှတ်ခြင်း ဖြစ်သည်။ dates များကို PHP မှ `strtotime` function ကို အသုံးပြု၍ passing ပေးသွားမည် ဖြစ်သည်။ +The field under validation must be a value preceding the given date. The dates will be passed into the PHP `strtotime` function. + + +#### before\_or\_equal:_date_ + +The field under validation must be a value preceding or equal to the given date. The dates will be passed into the PHP `strtotime` function. #### between:_min_,_max_ -အဆိုပါ field တွင်ထည့်သွင်းသော အချက်အလက်များ ၏ အများဆုံးနှင့် အနည်းဆုံး တန်ဖိုးများကို သတ်မှတ်ခြင်း ဖြစ်ပြီး String ၊ numeric နှင့် file များကို `size` rule ကို အသုံးပြုသကဲ့သို ့ ဆင်တင်တင်ပင် ဖြစ်သည်။ +The field under validation must have a size between the given _min_ and _max_. Strings, numerics, and files are evaluated in the same fashion as the [`size`](#rule-size) rule. + + +#### boolean + +The field under validation must be able to be cast as a boolean. Accepted input are `true`, `false`, `1`, `0`, `"1"`, and `"0"`. #### confirmed -အဆိုပါ field ၏ အချက်အလက်သည် ရည်ညွန်း field ၏ အချက်အလက် ဥပမာ `foo_confirmation` နှင့် တူညီရမည် ဖြစ်သည်။ ဥပမာ ပြုရသော် `password` field သည် `password_confirmation` field နှင့် ထပ်တူညီရမည် ဖြစ်သည်။ +The field under validation must have a matching field of `foo_confirmation`. For example, if the field under validation is `password`, a matching `password_confirmation` field must be present in the input. #### date -တိကျ မှန်ကန်သော date ဖြစ်စေရန် စိစစ်ပေးပြီး `strtotime` ဟူသော PHP function ကို အသုံးပြုထားသည်။ +The field under validation must be a valid date according to the `strtotime` PHP function. #### date_format:_format_ -အဆိုပါ field မှ format နှင့် တူညီရမည် ဖြစ်ပြီး `date_parse_from_format` ဟူသည် PHP function ကို အသုံးပြုထားသည်။ +The field under validation must match the given _format_. You should use **either** `date` or `date_format` when validating a field, not both. #### different:_field_ -အဆိုပါ field သည် အခြား ရည်ညွန်း field နှင့် လုံးဝ ကွဲပြားခြားရမည် ဖြစ်သည်။ -The given _field_ must be different than the field under validation. +The field under validation must have a different value than _field_. #### digits:_value_ -အဆိုပါ file တွင် numeric value ဖြစ်ပြီး တိကျသေချာသော ဂဏန်း အလုံးအရေအတွက် ကိုသာ ထည့်သွင်းရမည်ဖြစ်သည်။ +The field under validation must be _numeric_ and must have an exact length of _value_. #### digits_between:_min_,_max_ -အဆို field တွင် _min_ and _max_ အကြား ထည့်သွင်းရသော ဂဏန်းအလုံးအရေအတွက်ကိုသာ ထည့်သွင်းခွင့်ရမည်ဖြစ်သည်။ +The field under validation must have a length between the given _min_ and _max_. + + +#### dimensions + +The file under validation must be an image meeting the dimension constraints as specified by the rule's parameters: + + 'avatar' => 'dimensions:min_width=100,min_height=200' + +Available constraints are: _min\_width_, _max\_width_, _min\_height_, _max\_height_, _width_, _height_, _ratio_. + +A _ratio_ constraint should be represented as width divided by height. This can be specified either by a statement like `3/2` or a float like `1.5`: + + 'avatar' => 'dimensions:ratio=3/2' + +Since this rule requires several arguments, you may use the `Rule::dimensions` method to fluently construct the rule: + + use Illuminate\Validation\Rule; + + Validator::make($data, [ + 'avatar' => [ + 'required', + Rule::dimensions()->maxWidth(1000)->maxHeight(500)->ratio(3 / 2), + ], + ]); + + +#### distinct + +When working with arrays, the field under validation must not have any duplicate values. + + 'foo.*.id' => 'distinct' #### email -အဆိုပါ field တွင် email address format အတိုင်း ထည့်သွင်းထားခြင်း ရှိမရှိ စစ်ဆေးသွားမည် ဖြစ်သည်။ +The field under validation must be formatted as an e-mail address. #### exists:_table_,_column_ @@ -285,44 +694,99 @@ The field under validation must exist on a given database table. #### Basic Usage Of Exists Rule - 'state' => 'exists:states' + 'state' => 'exists:states' #### Specifying A Custom Column Name - 'state' => 'exists:states,abbreviation' + 'state' => 'exists:states,abbreviation' + +Occasionally, you may need to specify a specific database connection to be used for the `exists` query. You can accomplish this by prepending the connection name to the table name using "dot" syntax: + + 'email' => 'exists:connection.staff,email' + +If you would like to customize the query executed by the validation rule, you may use the `Rule` class to fluently define the rule. In this example, we'll also specify the validation rules as an array instead of using the `|` character to delimit them: + + use Illuminate\Validation\Rule; -You may also specify more conditions that will be added as "where" clauses to the query: + Validator::make($data, [ + 'email' => [ + 'required', + Rule::exists('staff')->where(function ($query) { + $query->where('account_id', 1); + }), + ], + ]); - 'email' => 'exists:staff,email,account_id,1' + +#### file -Passing `NULL` as a "where" clause value will add a check for a `NULL` database value: +The field under validation must be a successfully uploaded file. - 'email' => 'exists:staff,email,deleted_at,NULL' + +#### filled + +The field under validation must not be empty when it is present. #### image -The file under validation must be an image (jpeg, png, bmp, or gif) +The file under validation must be an image (jpeg, png, bmp, gif, or svg) #### in:_foo_,_bar_,... -The field under validation must be included in the given list of values. +The field under validation must be included in the given list of values. Since this rule often requires you to `implode` an array, the `Rule::in` method may be used to fluently construct the rule: + + use Illuminate\Validation\Rule; + + Validator::make($data, [ + 'zones' => [ + 'required', + Rule::in(['first-zone', 'second-zone']), + ], + ]); + + +#### in_array:_anotherfield_ + +The field under validation must exist in _anotherfield_'s values. #### integer -The field under validation must have an integer value. +The field under validation must be an integer. #### ip -The field under validation must be formatted as an IP address. +The field under validation must be an IP address. + +#### ipv4 + +The field under validation must be an IPv4 address. + +#### ipv6 + +The field under validation must be an IPv6 address. + + +#### json + +The field under validation must be a valid JSON string. #### max:_value_ -The field under validation must be less than or equal to a maximum _value_. Strings, numerics, and files are evaluated in the same fashion as the `size` rule. +The field under validation must be less than or equal to a maximum _value_. Strings, numerics, and files are evaluated in the same fashion as the [`size`](#rule-size) rule. + + +#### mimetypes:_text/plain_,... + +The file under validation must match one of the given MIME types: + + 'video' => 'mimetypes:video/avi,video/mpeg,video/quicktime' + +To determine the MIME type of the uploaded file, the file's contents will be read and the framework will attempt to guess the MIME type, which may be different from the client provided MIME type. #### mimes:_foo_,_bar_,... @@ -331,12 +795,21 @@ The file under validation must have a MIME type corresponding to one of the list #### Basic Usage Of MIME Rule - 'photo' => 'mimes:jpeg,bmp,png' + 'photo' => 'mimes:jpeg,bmp,png' + +Even though you only need to specify the extensions, this rule actually validates against the MIME type of the file by reading the file's contents and guessing its MIME type. + +A full listing of MIME types and their corresponding extensions may be found at the following location: [https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types](https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types) #### min:_value_ -The field under validation must have a minimum _value_. Strings, numerics, and files are evaluated in the same fashion as the `size` rule. +The field under validation must have a minimum _value_. Strings, numerics, and files are evaluated in the same fashion as the [`size`](#rule-size) rule. + + +#### nullable + +The field under validation may be `null`. This is particularly useful when validating primitive such as strings and integers that can contain `null` values. #### not_in:_foo_,_bar_,... @@ -346,7 +819,12 @@ The field under validation must not be included in the given list of values. #### numeric -The field under validation must have a numeric value. +The field under validation must be numeric. + + +#### present + +The field under validation must be present in the input data but can be empty. #### regex:_pattern_ @@ -358,32 +836,46 @@ The field under validation must match the given regular expression. #### required -The field under validation must be present in the input data. +The field under validation must be present in the input data and not empty. A field is considered "empty" if one of the following conditions are true: + +
    + +- The value is `null`. +- The value is an empty string. +- The value is an empty array or empty `Countable` object. +- The value is an uploaded file with no path. + +
    -#### required\_if:_field_,_value_ +#### required_if:_anotherfield_,_value_,... + +The field under validation must be present and not empty if the _anotherfield_ field is equal to any _value_. -The field under validation must be present if the _field_ field is equal to _value_. + +#### required_unless:_anotherfield_,_value_,... + +The field under validation must be present and not empty unless the _anotherfield_ field is equal to any _value_. #### required_with:_foo_,_bar_,... -The field under validation must be present _only if_ any of the other specified fields are present. +The field under validation must be present and not empty _only if_ any of the other specified fields are present. #### required_with_all:_foo_,_bar_,... -The field under validation must be present _only if_ all of the other specified fields are present. +The field under validation must be present and not empty _only if_ all of the other specified fields are present. #### required_without:_foo_,_bar_,... -The field under validation must be present _only when_ any of the other specified fields are not present. +The field under validation must be present and not empty _only when_ any of the other specified fields are not present. #### required_without_all:_foo_,_bar_,... -The field under validation must be present _only when_ the all of the other specified fields are not present. +The field under validation must be present and not empty _only when_ all of the other specified fields are not present. #### same:_field_ @@ -393,173 +885,202 @@ The given _field_ must match the field under validation. #### size:_value_ -The field under validation must have a size matching the given _value_. For string data, _value_ corresponds to the number of characters. For numeric data, _value_ corresponds to a given integer value. For files, _size_ corresponds to the file size in kilobytes. +The field under validation must have a size matching the given _value_. For string data, _value_ corresponds to the number of characters. For numeric data, _value_ corresponds to a given integer value. For an array, _size_ corresponds to the `count` of the array. For files, _size_ corresponds to the file size in kilobytes. - -#### unique:_table_,_column_,_except_,_idColumn_ + +#### string -The field under validation must be unique on a given database table. If the `column` option is not specified, the field name will be used. +The field under validation must be a string. If you would like to allow the field to also be `null`, you should assign the `nullable` rule to the field. -#### Basic Usage Of Unique Rule + +#### timezone - 'email' => 'unique:users' +The field under validation must be a valid timezone identifier according to the `timezone_identifiers_list` PHP function. -#### Specifying A Custom Column Name + +#### unique:_table_,_column_,_except_,_idColumn_ - 'email' => 'unique:users,email_address' +The field under validation must be unique in a given database table. If the `column` option is not specified, the field name will be used. -#### Forcing A Unique Rule To Ignore A Given ID +**Specifying A Custom Column Name:** - 'email' => 'unique:users,email_address,10' + 'email' => 'unique:users,email_address' -#### Adding Additional Where Clauses +**Custom Database Connection** -You may also specify more conditions that will be added as "where" clauses to the query: +Occasionally, you may need to set a custom connection for database queries made by the Validator. As seen above, setting `unique:users` as a validation rule will use the default database connection to query the database. To override this, specify the connection and the table name using "dot" syntax: - 'email' => 'unique:users,email_address,NULL,id,account_id,1' + 'email' => 'unique:connection.users,email_address' -In the rule above, only rows with an `account_id` of `1` would be included in the unique check. +**Forcing A Unique Rule To Ignore A Given ID:** - -#### url +Sometimes, you may wish to ignore a given ID during the unique check. For example, consider an "update profile" screen that includes the user's name, e-mail address, and location. Of course, you will want to verify that the e-mail address is unique. However, if the user only changes the name field and not the e-mail field, you do not want a validation error to be thrown because the user is already the owner of the e-mail address. -The field under validation must be formatted as an URL. +To instruct the validator to ignore the user's ID, we'll use the `Rule` class to fluently define the rule. In this example, we'll also specify the validation rules as an array instead of using the `|` character to delimit the rules: -> **Note:** This function uses PHP's `filter_var` method. + use Illuminate\Validation\Rule; - -## Conditionally Adding Rules + Validator::make($data, [ + 'email' => [ + 'required', + Rule::unique('users')->ignore($user->id), + ], + ]); -In some situations, you may wish to run validation checks against a field **only** if that field is present in the input array. To quickly accomplish this, add the `sometimes` rule to your rule list: +If your table uses a primary key column name other than `id`, you may specify the name of the column when calling the `ignore` method: - $v = Validator::make($data, array( - 'email' => 'sometimes|required|email', - )); + 'email' => Rule::unique('users')->ignore($user->id, 'user_id') -In the example above, the `email` field will only be validated if it is present in the `$data` array. +**Adding Additional Where Clauses:** -#### Complex Conditional Validation +You may also specify additional query constraints by customizing the query using the `where` method. For example, let's add a constraint that verifies the `account_id` is `1`: -Sometimes you may wish to require a given field only if another field has a greater value than 100. Or you may need two fields to have a given value only when another field is present. Adding these validation rules doesn't have to be a pain. First, create a `Validator` instance with your _static rules_ that never change: + 'email' => Rule::unique('users')->where(function ($query) { + $query->where('account_id', 1); + }) - $v = Validator::make($data, array( - 'email' => 'required|email', - 'games' => 'required|numeric', - )); + +#### url -Let's assume our web application is for game collectors. If a game collector registers with our application and they own more than 100 games, we want them to explain why they own so many games. For example, perhaps they run a game re-sell shop, or maybe they just enjoy collecting. To conditionally add this requirement, we can use the `sometimes` method on the `Validator` instance. +The field under validation must be a valid URL. - $v->sometimes('reason', 'required|max:500', function($input) - { - return $input->games >= 100; - }); + +## Conditionally Adding Rules -The first argument passed to the `sometimes` method is the name of the field we are conditionally validating. The second argument is the rules we want to add. If the `Closure` passed as the third argument returns `true`, the rules will be added. This method makes it a breeze to build complex conditional validations. You may even add conditional validations for several fields at once: +#### Validating When Present - $v->sometimes(array('reason', 'cost'), 'required', function($input) - { - return $input->games >= 100; - }); +In some situations, you may wish to run validation checks against a field **only** if that field is present in the input array. To quickly accomplish this, add the `sometimes` rule to your rule list: -> **Note:** The `$input` parameter passed to your `Closure` will be an instance of `Illuminate\Support\Fluent` and may be used as an object to access your input and files. + $v = Validator::make($data, [ + 'email' => 'sometimes|required|email', + ]); - -## Custom Error Messages +In the example above, the `email` field will only be validated if it is present in the `$data` array. -If needed, you may use custom error messages for validation instead of the defaults. There are several ways to specify custom messages. +#### Complex Conditional Validation -#### Passing Custom Messages Into Validator +Sometimes you may wish to add validation rules based on more complex conditional logic. For example, you may wish to require a given field only if another field has a greater value than 100. Or, you may need two fields to have a given value only when another field is present. Adding these validation rules doesn't have to be a pain. First, create a `Validator` instance with your _static rules_ that never change: - $messages = array( - 'required' => 'The :attribute field is required.', - ); + $v = Validator::make($data, [ + 'email' => 'required|email', + 'games' => 'required|numeric', + ]); - $validator = Validator::make($input, $rules, $messages); +Let's assume our web application is for game collectors. If a game collector registers with our application and they own more than 100 games, we want them to explain why they own so many games. For example, perhaps they run a game resale shop, or maybe they just enjoy collecting. To conditionally add this requirement, we can use the `sometimes` method on the `Validator` instance. -> *Note:* The `:attribute` place-holder will be replaced by the actual name of the field under validation. You may also utilize other place-holders in validation messages. + $v->sometimes('reason', 'required|max:500', function ($input) { + return $input->games >= 100; + }); -#### Other Validation Place-Holders +The first argument passed to the `sometimes` method is the name of the field we are conditionally validating. The second argument is the rules we want to add. If the `Closure` passed as the third argument returns `true`, the rules will be added. This method makes it a breeze to build complex conditional validations. You may even add conditional validations for several fields at once: - $messages = array( - 'same' => 'The :attribute and :other must match.', - 'size' => 'The :attribute must be exactly :size.', - 'between' => 'The :attribute must be between :min - :max.', - 'in' => 'The :attribute must be one of the following types: :values', - ); + $v->sometimes(['reason', 'cost'], 'required', function ($input) { + return $input->games >= 100; + }); -#### Specifying A Custom Message For A Given Attribute +> {tip} The `$input` parameter passed to your `Closure` will be an instance of `Illuminate\Support\Fluent` and may be used to access your input and files. -Sometimes you may wish to specify a custom error messages only for a specific field: + +## Validating Arrays - $messages = array( - 'email.required' => 'We need to know your e-mail address!', - ); +Validating array based form input fields doesn't have to be a pain. For example, to validate that each e-mail in a given array input field is unique, you may do the following: - -#### Specifying Custom Messages In Language Files + $validator = Validator::make($request->all(), [ + 'person.*.email' => 'email|unique:users', + 'person.*.first_name' => 'required_with:person.*.last_name', + ]); -In some cases, you may wish to specify your custom messages in a language file instead of passing them directly to the `Validator`. To do so, add your messages to `custom` array in the `app/lang/xx/validation.php` language file. +Likewise, you may use the `*` character when specifying your validation messages in your language files, making it a breeze to use a single validation message for array based fields: - 'custom' => array( - 'email' => array( - 'required' => 'We need to know your e-mail address!', - ), - ), + 'custom' => [ + 'person.*.email' => [ + 'unique' => 'Each person must have a unique e-mail address', + ] + ], ## Custom Validation Rules -#### Registering A Custom Validation Rule - -Laravel provides a variety of helpful validation rules; however, you may wish to specify some of your own. One method of registering custom validation rules is using the `Validator::extend` method: +Laravel provides a variety of helpful validation rules; however, you may wish to specify some of your own. One method of registering custom validation rules is using the `extend` method on the `Validator` [facade](/docs/{{version}}/facades). Let's use this method within a [service provider](/docs/{{version}}/providers) to register a custom validation rule: + + "Your input was invalid!", -#### Extending The Validator Class + "accepted" => "The :attribute must be accepted.", -Instead of using Closure callbacks to extend the Validator, you may also extend the Validator class itself. To do so, write a Validator class that extends `Illuminate\Validation\Validator`. You may add validation methods to the class by prefixing them with `validate`: + // The rest of the validation error messages... - 'unique']; - Validator::resolver(function($translator, $data, $rules, $messages) - { - return new CustomValidator($translator, $data, $rules, $messages); - }); + $input = ['name' => null]; -When creating a custom validation rule, you may sometimes need to define custom place-holder replacements for error messages. You may do so by creating a custom Validator as described above, and adding a `replaceXXX` function to the validator. + Validator::make($input, $rules)->passes(); // true - protected function replaceFoo($message, $attribute, $rule, $parameters) - { - return str_replace(':foo', $parameters[0], $message); - } +For a rule to run even when an attribute is empty, the rule must imply that the attribute is required. To create such an "implicit" extension, use the `Validator::extendImplicit()` method: -If you would like to add a custom message "replacer" without extending the `Validator` class, you may use the `Validator::replacer` method: + Validator::extendImplicit('foo', function ($attribute, $value, $parameters, $validator) { + return $value == 'foo'; + }); - Validator::replacer('rule', function($message, $attribute, $rule, $parameters) - { - // - }); \ No newline at end of file +> {note} An "implicit" extension only _implies_ that the attribute is required. Whether it actually invalidates a missing or empty attribute is up to you. diff --git a/views.md b/views.md new file mode 100644 index 0000000..80e2063 --- /dev/null +++ b/views.md @@ -0,0 +1,200 @@ +# Views + +- [Creating Views](#creating-views) +- [Passing Data To Views](#passing-data-to-views) + - [Sharing Data With All Views](#sharing-data-with-all-views) +- [View Composers](#view-composers) + + +## Creating Views + +Views contain the HTML served by your application and separate your controller / application logic from your presentation logic. Views are stored in the `resources/views` directory. A simple view might look something like this: + + + + + +

    Hello, {{ $name }}

    + + + +Since this view is stored at `resources/views/greeting.blade.php`, we may return it using the global `view` helper like so: + + Route::get('/', function () { + return view('greeting', ['name' => 'James']); + }); + +As you can see, the first argument passed to the `view` helper corresponds to the name of the view file in the `resources/views` directory. The second argument is an array of data that should be made available to the view. In this case, we are passing the `name` variable, which is displayed in the view using [Blade syntax](/docs/{{version}}/blade). + +Of course, views may also be nested within sub-directories of the `resources/views` directory. "Dot" notation may be used to reference nested views. For example, if your view is stored at `resources/views/admin/profile.blade.php`, you may reference it like so: + + return view('admin.profile', $data); + +#### Determining If A View Exists + +If you need to determine if a view exists, you may use the `View` facade. The `exists` method will return `true` if the view exists: + + use Illuminate\Support\Facades\View; + + if (View::exists('emails.customer')) { + // + } + + +## Passing Data To Views + +As you saw in the previous examples, you may pass an array of data to views: + + return view('greetings', ['name' => 'Victoria']); + +When passing information in this manner, `$data` should be an array with key/value pairs. Inside your view, you can then access each value using its corresponding key, such as ``. As an alternative to passing a complete array of data to the `view` helper function, you may use the `with` method to add individual pieces of data to the view: + + return view('greeting')->with('name', 'Victoria'); + + +#### Sharing Data With All Views + +Occasionally, you may need to share a piece of data with all views that are rendered by your application. You may do so using the view facade's `share` method. Typically, you should place calls to `share` within a service provider's `boot` method. You are free to add them to the `AppServiceProvider` or generate a separate service provider to house them: + + +## View Composers + +View composers are callbacks or class methods that are called when a view is rendered. If you have data that you want to be bound to a view each time that view is rendered, a view composer can help you organize that logic into a single location. + +For this example, let's register the view composers within a [service provider](/docs/{{version}}/providers). We'll use the `View` facade to access the underlying `Illuminate\Contracts\View\Factory` contract implementation. Remember, Laravel does not include a default directory for view composers. You are free to organize them however you wish. For example, you could create an `App\Http\ViewComposers` directory: + + {note} Remember, if you create a new service provider to contain your view composer registrations, you will need to add the service provider to the `providers` array in the `config/app.php` configuration file. + +Now that we have registered the composer, the `ProfileComposer@compose` method will be executed each time the `profile` view is being rendered. So, let's define the composer class: + + users = $users; + } + + /** + * Bind data to the view. + * + * @param View $view + * @return void + */ + public function compose(View $view) + { + $view->with('count', $this->users->count()); + } + } + +Just before the view is rendered, the composer's `compose` method is called with the `Illuminate\View\View` instance. You may use the `with` method to bind data to the view. + +> {tip} All view composers are resolved via the [service container](/docs/{{version}}/container), so you may type-hint any dependencies you need within a composer's constructor. + +#### Attaching A Composer To Multiple Views + +You may attach a view composer to multiple views at once by passing an array of views as the first argument to the `composer` method: + + View::composer( + ['profile', 'dashboard'], + 'App\Http\ViewComposers\MyViewComposer' + ); + +The `composer` method also accepts the `*` character as a wildcard, allowing you to attach a composer to all views: + + View::composer('*', function ($view) { + // + }); + +#### View Creators + +View **creators** are very similar to view composers; however, they are executed immediately after the view is instantiated instead of waiting until the view is about to render. To register a view creator, use the `creator` method: + + View::creator('profile', 'App\Http\ViewCreators\ProfileCreator'); From 71b2e423a025350be23555f06854ada053a241a9 Mon Sep 17 00:00:00 2001 From: Set Kyar Wa Lar Date: Sat, 4 Feb 2017 12:43:38 +0630 Subject: [PATCH 4/5] translate readme and contributing --- contributing.md | 18 ++++++++++++++++-- readme.md | 15 ++++++++++++--- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/contributing.md b/contributing.md index e68c3d3..266c057 100644 --- a/contributing.md +++ b/contributing.md @@ -1,3 +1,17 @@ -# Contribution Guidelines +# ပူးပေါင်းပါဝင်မှု လမ်းညွန် -If you are submitting documentation for the **current stable release**, submit it to the corresponding branch. For example, documentation for Laravel 5.1 would be submitted to the `5.1` branch. Documentation intended for the next release of Laravel should be submitted to the `master` branch. \ No newline at end of file +###ဘာသာပြန်ခြင်း + + - ကျွန်တော်တို့ကို ပူးပေါင်းပါဝင် ကူညီပြီးဘာသာပြန်ချင်တယ်ဆိုရင် + [docs](https://github.com/setkyar/laravel-docs/) ကိုဦးစွာ Fork လုပ်ပါ၊ + + - ဘယ်အပိုင်းကို ဘာသာပြန်မည်ဆိုတာကို [Facebook](https://www.facebook.com/groups/250409601822202/) မှာပြောပေးပါ။ (Fork + လုပ်ပြီးဘာသာပြန်နေတုန်းအခြားတစ်ယောက်ယောက်ကပါဘာသာပြန်နေတာမျိုးဖြစ်မှာစိုးလို့ပါ) + + - သင်ဘာသာပြန်မည့် File ကိုဘာသာပြန်ပါ။ ဘာသာပြန်ပြီးရင် မူရင်း repo ဆီက + [pull request](https://github.com/setkyar/laravel-docs/pulls) တောင်းပါ။ (pull request တောင်းတာကို မြန်မြန် accept + လုပ်စေချင်တယ်ဆိုရင်[Facebook]( https://www.facebook.com/groups/250409601822202/) မှာပါတင်ပေးပါ) + +###ဘာသာပြန်အဆင်ပြေမှူနှင့် စာလုံးပေါင်းအမှား + +ဘာသာပြန်ထားတာတွေ ကိုဦးစွာဖတ်ပါ။ ဘာသာပြန်အဆင်ပြေမှူ နဲ့ စာလုံးပေါင်း အမှားတွေကို စစ်ပါ။ ဘာသာပြန်အဆင်ပြေမှူမရှိတာတို့ စာလုံးပေါင်းအမှားတွေတွေ့ရင် GitHub မှာ [issue](https://github.com/setkyar/laravel-docs/issues) တင်ပေးပါ။(အမှားတွေကို အမြန်ဆုံး စစ်ပေးဖို့ [Facebook](https://www.facebook.com/groups/250409601822202/) မှာပါတင်ပေးပါ) diff --git a/readme.md b/readme.md index 9b55bba..6539e3d 100644 --- a/readme.md +++ b/readme.md @@ -1,5 +1,14 @@ -# Laravel Documentation +ရည်ရွယ်ချက် +--------- -## Contribution Guidelines +ကျွန်တော်တို့ အခုမှစပြီး ဘာသာပြန်နေတုံးပါ၊ ရည်ရွယ်ချက် ကတော့ Laravel PHP Framework Documencation ကို မြန်မာလို ဖတ်ပြီး Laravel Framework ကို အလွယ်တကူ လေ့လာနိုင်ဖို့ပါ၊ -If you are submitting documentation for the **current stable release**, submit it to the corresponding branch. For example, documentation for Laravel 5.1 would be submitted to the `5.1` branch. Documentation intended for the next release of Laravel should be submitted to the `master` branch. +ဒီဘာသာပြန်မှုမှာ ဘယ်လို ဘာဝင်ကူညီနိုင်လဲ +-------------------- + +ဟုတ်ကဲ့ ကျွန်တော်တို့လည်းအလုပ်နဲ့ပါ အားတဲ့အချိန်လေးဘာသာပြန်ပြီးတော့ဒီမှာတင်တာပါ။ တကယ်လို့ကျွန်တော်တို့ကို ကူညီပြီးဘာသာပြန်ချင်တယ်ဆိုရင်ဒီ Repo မှာ pull request လုပ်ပြီး contribute လုပ်နိုင်ပါတယ်။ ကျွန်တော်တို့ဘာသာပြန်ပြီးသားတွေကိုလည်း စာလုံးပေါင်းအမှားတွေကို git issue တွေပေးနိုင်ပါတယ်။ [Contribute Guide](contributing.md) ကိုဖတ်ပေးပါ။ + +ဆက်သွယ်ရန် +------- + +- [Laravel Myanmar Facebook Group](https://www.facebook.com/groups/250409601822202/) \ No newline at end of file From 6627257943f6848285017d5a9109128a27ed3f67 Mon Sep 17 00:00:00 2001 From: Set Kyar Wa Lar Date: Sat, 4 Feb 2017 13:02:21 +0630 Subject: [PATCH 5/5] add for gitbook --- .gitignore | 2 ++ package.json | 24 ++++++++++++++++++++++++ summary.md | 8 ++++++++ 3 files changed, 34 insertions(+) create mode 100644 .gitignore create mode 100644 package.json create mode 100644 summary.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e9560ce --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +_book/ +node_modules/ \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..8e62f29 --- /dev/null +++ b/package.json @@ -0,0 +1,24 @@ +{ + "name": "5.4", + "version": "1.0.0", + "description": "## Contribution Guidelines", + "main": "index.js", + "scripts": { + "docs:prepare": "gitbook install", + "docs:watch": "npm run docs:prepare && gitbook serve", + "docs:build": "npm run docs:prepare && rm -rf _book && gitbook build" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/setkyar/laravel-docs.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/setkyar/laravel-docs/issues" + }, + "homepage": "https://github.com/setkyar/laravel-docs#readme", + "devDependencies": { + "gitbook-cli": "^2.3.0" + } +} diff --git a/summary.md b/summary.md new file mode 100644 index 0000000..751ad31 --- /dev/null +++ b/summary.md @@ -0,0 +1,8 @@ +# Summary + +* [Introduction](readme.md) +* Getting Started + * [Installation](installation.md) + * [Configuration](configuration.md) + * [Directory Structure](structure.md) + * [Errors & Logging](errors.md) \ No newline at end of file