diff --git a/SUMMARY.md b/SUMMARY.md deleted file mode 100644 index 756b6fa..0000000 --- a/SUMMARY.md +++ /dev/null @@ -1,27 +0,0 @@ -# Table of contents - -* [Yuga Framework](README.md) -* [Routing](basic-routing.md) -* [Middleware](middleware.md) -* [Controllers](controllers.md) -* [ViewModels](view-models.md) -* [Database](database/README.md) - * [Elegant](database/elegant/README.md) - * [Relationships](database/elegant/relationships.md) - * [Complex queries](database/elegant/complex-queries.md) - * [Events](database/elegant/events.md) - * [Query](database/query.md) - * [Migrations](database/migrations.md) -* [Events](events/README.md) - * [Event Classes](events/event-classes.md) - * [Event Handlers](events/event-handlers.md) -* [Service Providers](service-providers.md) -* [Views](views/README.md) - * [MVC](views/mvc/README.md) - * [Hax Templates](views/mvc/hax-templates.md) - * [MVVM](views/mvvm.md) -* [Helpers](help-functions.md) -* [Schedulers](schedulers.md) -* [Queue worker](queue-worker.md) -* [Commands](commands/README.md) - * [Scaffold](commands/scaffold.md) diff --git a/basic-routing.md b/basic-routing.md deleted file mode 100644 index 1d0068c..0000000 --- a/basic-routing.md +++ /dev/null @@ -1,314 +0,0 @@ ---- -description: >- - Routing allows you to customize your URLs by specifying which URL patterns - refer to which controllers and actions or ViewModels. ---- - -# Routing - -## Routing - -#### Building routes for your application is one way of linking pages through out the entire application. We have quite a few ways you can do that as follows - -### Routing - -**Basic Routing** - -The most basic Yuga routes accept a URI and a `Callback`, providing a very simple and expressive method of defining routes: - -```php -Route::get('hello', function () { - return 'Hello World'; -}); -``` - -**The Default Route Files** - -All Yuga routes are defined in your routes file, which are located in the `routes` directory. This file is automatically loaded by the framework. The `routes/web.php` file defines routes that are for your web application. These routes automatically have CSRF protection. - -**Available Router Methods** - -The router allows you to register routes that respond to any HTTP verb: - -```php -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::basic($uri, $callback); -Route::form($uri, $callback); -``` - -Sometimes you may need to use a route that calls multiple HTTP verbs. You can do this by using the `match` method. Or, you may even register a route that responds to all HTTP verbs using the `all`method: - -```php -Route::match(['get', 'post'], '/', function () { - // your code -}); - -Route::all('foo', function () { - // your code -}); -``` - -**Route Parameters** - -**Required Parameters** - -When ever you need to get sections of the URI within your route, this approach might come in handy. E.g. you may want to get the post's id from the URL, you can do that by defining the route parameters: - -```php -Route::get('post/{id}', function ($id) { - return 'Post with id: ' . $id; -}); -``` - -You may define as many route parameters as required by your route: - -```php -Route::get('posts/{post}/comments/{comment}', function ($post, $comment) { - // your code -}); -``` - -Route parameters are always encased within `{}` braces and should consist of alphabetic characters, and may not contain a `-` character. Instead of using the `-` character, use an underscore \(`_`\). Route parameters are injected into route callbacks / controllers based on their names in the Route defined, the order of getting them in callback / controller does not matter. - -**Optional Parameters** - -Sometimes you may need to specify a route parameter, but make its presence optional, you can do that by placing `?` after the parameter name either in the callback or the controller in which you will use the parameter. Make sure to give an optional parameter a default value in your callback / controller: - -```php -Route::get('user/{name?}', function ($name = null) { - return $name; -}); - -Route::get('user/{name?}', function ($name = 'Hamnaj') { - return $name; -}); -``` - -**Regular Expression Constraints** - -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: - -```php -Route::get('user/{id}', function ($id) { - // your code -})->where('id', '[0-9]+'); - -Route::get('user/{id}/{name}', function ($id, $name) { - // your code -})->where(['id' => '[0-9]+', 'name' => '[a-z]+']); -``` - -**Named Routes** - -Named routes allow you to conveniently make URLs or redirects for specific routes. You can specify a name for a route by chaining the `name` method onto the route definition: - -```php -Route::get('user/posts', function () { - // your code -})->name('posts'); -``` - -You may also specify route names for controller actions: - -```php -Route::get('user/posts', 'UserPostController@get')->name('posts'); -``` - -**Generating URLs To Named Routes** - -After giving a name to a route, you can use the route's name in generating the URLs or redirects using the `route` function: - -```php -// Creating URLs -$url = route('posts'); - -// Creating Redirects -return redirect()->route('posts'); -``` - -If the named route defines parameters, you can 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: - -```php -Route::get('user/{id}/posts', function ($id) { - // your code -})->name('posts'); - -$url = route('posts', ['id' => 1]); -``` - -**Form Method Spoofing** - -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: - -```php - -``` - -**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. - -**Middleware** - -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: - -```php -Route::group(['middleware' => 'auth'], function () { - Route::get('/', function () { - // Uses Auth Middleware - }); - - Route::get('/user/profile', function () { - // Uses Auth Middleware - }); -}); -``` - -**Namespaces** - -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: - -**Note** - -Group namespaces will only be added to routes with relative callbacks. For example if your route has an absolute callback like `\App\Controllers\DashboardController@home`, the namespace from the route will not be prepended. To fix this you can make the callback relative by removing the `\` in the beginning of the callback. - -```php -Route::group(['namespace' => 'Admin'], function () { - // Controllers Within The "App\Controllers\Admin" Namespace -}); -``` - -**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 get a portion of the sub-domain for usage in your route or controller. The sub-domain may be specified using the `domain` keyword on the group attribute array: - -```php -Route::group(['domain' => '{account}.myapp.com'], function () { - Route::get('/user/{id}', function ($account, $id) { - // - }); -}); -``` - -**Route prefixes** - -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`: - -```php -Route::group(['prefix' => '/admin'], function () { - Route::get('/users', function () { - // Matches The "/admin/users" URL - }); -}); -``` - -**CSRF Protection** - -Any forms posting to `POST`, `PUT` or `DELETE` routes should include the CSRF-token. We strongly recommend that you create your enable CSRF-verification on your site. All you need to do in your forms is include this line - -```php -=token()?> -// or - -``` - -**Implicit Routing \(Mapping Routes to Controllers\)** - -Some developers that are used to the usual mvc route-to-controller mapping i.e `http://localhost:8000/home` would map to - -```php -// the route is /home maps to HomeController@index -(new App\Controllers\HomeController)->index(); -``` - -Yuga-framework supports that too but you must note that this comes turned off by default. It can be turned on by finding the `environment/.env` file and looking for `MATCH_ROUTES_TO_CONTROLLERS` and changing its value to true. - -Also note that the order of the routes is `/controller/method/arg1/arg2/args....whatever` When no controller is supplied in the `URI`, the router will default to `HomeController` and when no method is given, then it will default to `HomeController@index`, this can be changed by locating `ROUTE_DEFAULTS` variable in the `environment/.env` file and supplying it with a `json` string of the format - -```javascript -{"controller" : "Home", "method" : "index"} -``` - -Also note that for this to work, the router makes an assumption of the controller living in `app/Controllers` directory and so with a namespace of `App\Controllers`. It also adds the word controller to the URI therefore `/home` is mapped to `HomeController`. - -**Page Focused Routing \(Mapping Routes to pages in the view directory\)** - -Some developers find it very hard to work with controllers and routes at the same time, besides having implicit routing, yuga-framework supports a page focused routing mechanism, in which a route of any depth is mapped directly to a page inside of the `resources/views/Pages/` directory. E.g - -```javascript -http://localhost:8000/home -``` - -Will be mapped to a page like. - -```javascript - -OR - -``` - -> Please note that implicit routing and page-focused routing don't get along, one of them must be turned off for the other to work. - -#### Configuration settings for page-focused routing. - -All settings for the framework are pretty much put in this file, this goes the same for page-focused routing as well, so locate the following variables and set them to your liking - -```javascript - -PREFIX_MVP_ROUTE="/pages" # Defaults for '/' -ENABLE_MVP_ROUTES=true # Defaults to false -MVP_CONTROLLER=PageController # Defaults to Controller -``` - -The following might be the structure of PageController. - -```javascript -namespace App\Controllers; - -use Yuga\Http\Request; - -class PageController extends Controller -{ - /** - * Any data that is caried down to the Test view - * Could be records from the database - */ - protected function renderTest() - { - $this->view->name = "Hamid"; - } - - /** - * Any data that is caried down to the Salaries view - * Could be records from the database - */ - protected function renderSalaries() - { - $this->view->name = "Jane Doe"; - $this->view->users = [ - ['id' => 1, 'name' => 'Jane Doe',], - ]; - } - - /** - * Posting a form from the Salaries view - * @param Request $request - */ - protected function onPostSalaries(Request $request) - { - /** - * You have access to the entire request object - * You can post to the database, send mails, or do any data processing - */ - dump($request->except(['_token'])); - return; - } - -} -``` - diff --git a/commands/README.md b/commands/README.md deleted file mode 100644 index 605c312..0000000 --- a/commands/README.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -description: Yuga commands ---- - -# Commands - diff --git a/commands/scaffold.md b/commands/scaffold.md deleted file mode 100644 index 5ae3d39..0000000 --- a/commands/scaffold.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -description: The scaffold command ---- - -# Scaffold - diff --git a/composer.json b/composer.json index 7b545fc..8df2f5c 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,8 @@ } ], "require": { - "yuga/framework": "^4.0" + "yuga/framework": "^4.0", + "yuga/repl": "^1.0" }, "require-dev": { "phpunit/phpunit": "^7.4|^8.0|^9.0" diff --git a/controllers.md b/controllers.md deleted file mode 100644 index 93ae5a9..0000000 --- a/controllers.md +++ /dev/null @@ -1,201 +0,0 @@ -# Controllers - -## Controllers - -Instead of defining all of your request handling logic as Closures in routes/web.php file, you may want to organise them using Controller classes. - -### Controllers can group related request handling logic. - -## Controllers - -Controllers are stored in the `app/Controllers` directory by default but in yuga, everything is configurable which means you can put them in `app/AnyFolder` and map them to the appropriate namespace - -#### [Basic Controllers](https://yuga-framework.gitbook.io/documentation/controllers#basic-controllers) - -**Defining Controllers** - -Below is an example of a basic controller class. Note that the controller extends the base controller class that comes with Yuga. The base class provides a few convenience methods such as the `middleware` method, which can be used to attach middleware to controller methods: - -```php -posts = $post; - } -} -``` - -You can also type-hint any Yuga classes and interfaces If the container can resolve them, you can type-hint them. - -**Method Injection** - -In addition to constructor injection, you can also type-hint dependencies on your controller's methods. A common use-case for method injection is injecting the `Yuga\Http\Request`instance into your controller methods: - -```php -get('name'); - } -} -``` - -If your controller method is also expecting input from a route parameter, list your route arguments any where with other dependencies, remember, Route parameters are injected into route callbacks / controllers based on their names in the Route defined, the order of getting them in callback / controller does not matter. For example, if your route is defined like so: - -```php -Route::put('user/{id}', 'UserController@save'); -``` - -You may still type-hint the `Yuga\Http\Request` and access your `id` parameter by defining your controller method as follows: - -```php -- - Database interaction is key in any application and the way yuga makes it easy, - is credibly wonderful ---- - -# Database - -## Introduction - -Yuga makes interacting with databases extremely simple across a variety of database backends using either raw SQL, the [fluent query builder](https://yuga-framework.gitbook.io/documentation/database/query), and the [Elegant ORM](https://yuga-framework.gitbook.io/documentation/database/elegant). Currently, Yuga supports three databases: - -* MySQL -* PostgreSQL -* SQLite - -### Configuration - -The database configuration for your application is located at `config/config.php`. In this file you can 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, Yuga comes configured to use mysql but comes with the `DATABASE_NAME` key in the `environment/.env` blank so, it does not connect to any database but once the database name is provided, it will connect automatically. - diff --git a/database/elegant.md b/database/elegant.md deleted file mode 100644 index 09f3f88..0000000 --- a/database/elegant.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -description: >- - The Elegant ORM is an Active Record implementation that allows you to interact - with the database using objects that are linked to database tables ---- - -# Elegant - -The Elegant ORM that comes with Yuga provides a beautiful, simple Active Record 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. - diff --git a/database/elegant/README.md b/database/elegant/README.md deleted file mode 100644 index 1d66f11..0000000 --- a/database/elegant/README.md +++ /dev/null @@ -1,452 +0,0 @@ ---- -description: >- - The Elegant ORM is an Active Record implementation that allows you to - interact with the database using objects that are linked to database tables ---- - -# Elegant - -The Elegant ORM that comes with Yuga provides a beautiful, simple Active Record 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. - -#### [Defining Models](https://yuga-framework.gitbook.io/documentation/database/elegant) - -To get started, let's create an Elegant model. Models typically live in the `app/Models` directory, but you are free to place them anywhere that can be auto-loaded according to your `composer.json`file. All Elegant models extend use `Yuga\Models\ElegantModel` class which also extends `Yuga\Database\Elegant\Model` class, typically, a model can extend `Yuga\Database\Elegant\Model` class directly - -The easiest way of creating a model instance is using the `make:model` yuga command - -```text -php yuga make:model User -``` - -**Elegant Model Conventions** - -Now, let's look at an example `User` model, which we will use to retrieve and store information from our `users` database table: - -```php - - -Once you have created a model and its associated database table, you are ready to start retrieving data from your database. Take it that each Elegant model is an improved [query builder](https://yuga-framework.gitbook.io/documentation/database/query) allowing you to fluently query the database table associated with the model. For example: - -```php -name; -} -``` - -**Adding Additional Constraints** - -The Elegant `all` method will return all of the results in the model's table. Since each Elegant model serves as a [query builder](https://yuga-framework.gitbook.io/documentation/database/query), you may also add constraints to queries, and then use the `get / all`method to retrieve the results: - -```php -$users = App\Models\User::where('active', 1) - ->orderBy('name', 'desc') - ->take(10) - ->get(); -// or - -$users = App\Models\User::where('active', 1) - ->orderBy('name', 'desc') - ->take(10) - ->all(); -``` - -> Since Elegant models are improved query builders, you may want to review all of the methods available on the [query builder](https://yuga-framework.gitbook.io/documentation/database/query). You may use any of these methods in your Elegant queries. - -**Collections** - -For Elegant methods like `all` and `get` which retrieve multiple results, an instance of `Yuga\Database\Elegant\Collection` will be returned. The `Collection` class provides a variety of helpful methods for working with your Elegant results: - -You can loop over the collection like an array: - -```php -foreach ($users as $user) { - echo $user->name; -} -``` - -**Chunking Results** - -If you need to process thousands of Elegant results, use the `chunk` method. The `chunk`method will retrieve a "chunk" of Elegant models, putting them to a given `Closure` for processing. Using the `chunk` method will conserve memory when working with large result sets: - -```php -User::chunk(200, function ($users) { - foreach ($users as $user) { - //your code - } -}); -``` - -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. - -#### Retrieving Single Models / Aggregates - -In addition to retrieving all of the records for a given table, you can also retrieve single records using `find`or `first` or `last` . Instead of returning a collection of models, these methods return a single model instance: - -```php -// Retrieve a model by its primary key... -$users = App\Models\User::find(1); - -// Retrieve the first model matching the query constraints... -$users = App\Models\User::where('active', 1)->first(); - -// Retrieve the last model matching the query constraints... -$users = App\Models\User::where('active', 1)->last(); -``` - -You may also call the `find` method with an array of primary keys, which will return a collection of the matching records: - -```php -$users = App\Models\User::find([1, 2, 3]); -``` - -**Retrieving Aggregates** - -You may also use the `count`, `sum`, `max`, and other aggregate methods provided by the [query builder](https://yuga-framework.gitbook.io/documentation/database/query). These methods return the appropriate scalar value instead of a full model instance: - -```php -$count = App\Models\User::where('active', 1)->count(); - -$sum = App\Models\Users::where('active', 1)->sum('admins'); -``` - -#### Inserting & Updating Models - -**Inserts** - -To create a new record in the database, create a new model instance, set attributes on the model, then call the `save` method: - -```php -name = $request->get('name'); - - $user->save(); - } -} -``` - -In this example, we assign the `name` array key from the incoming HTTP request `get` method to the `name`attribute of the `App\Models\User` 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** - -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: - -```php -$user = App\Models\User::find(1); - -$user->name = 'Hamnaj'; - -$user->save(); -``` - -**Mass Updates** - -Updates can also be performed against any number of models that match a given query. In this example, all users that are `active` and have a `duty role` as true: - -```php -$users = App\Models\User::where('active', 1) - ->where('on_duty', false) - ->update(['on_duty' => 1]); -// or -$users = App\Models\User::where('active', 1) - ->where('on_duty', false) - ->save(['on_duty' => 1]); -``` - -The `update / save` method expects an array of column and value pairs representing the columns that should be updated. - -**Mass Assignment** - -You may also use the model's `__contruct` 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` - -```php - 'Hamnaj']))->save(); -``` - -**Other Creation Methods** - -**create/ firstOrCreate/ firstOrNew** - -There are three other methods you may use to create models by mass assigning attributes: `create`, `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 attributes from the first parameter, along with those in the optional second parameter. - -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: - -```php -// Retrieve user by name, or create it if it doesn't exist... -$user = App\Models\User::firstOrCreate(['name' => 'Hamnaj']); - -// Retrieve user by name, or create it with the name and admin attributes... -$user = App\Models\User::firstOrCreate([ - 'name' => 'Hamnaj', - 'admin' => 1 -]); - -// Retrieve by name, or instantiate... -$user = App\Models\User::firstOrNew(['name' => 'Hamnaj']); - -// Retrieve by name, or instantiate with the name and admin attributes... -$user = App\Models\User::firstOrNew([ - 'name' => 'Hamnaj', - 'admin' => 1 -]); - -// Create a user with the create method -$user = App\Models\User::create([ - 'name' => 'Hamnaj' -]); -``` - -**updateOrCreate** - -You may also come across situations where you want to update an existing model or create a new model if none exists. Elegant 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()`: - -```php -// If there's a user whose name is jakat update the other field(age) -// If no matching model exists, create one. -$user = App\Models\User::updateOrCreate( - ['name' => 'Jakat',], - ['age' => 30,] -); -``` - -#### [Deleting Models](https://yuga-framework.gitbook.io/documentation/elegant#deleting-models) - -To delete a model, call the `delete` method on a model instance: - -```php -$user = App\Models\User::find(1); - -$user->delete(); -``` - -By default Elegant will `soft delete` database results when the `delete` method is called on a `model`. To delete a result or a set of results \(force delete\), a `\Yuga\Database\Elegant\Traits\PermanentDeleteTrait`trait must be used in a model, once that trait is used, - -```php -', 10000); - -$users->delete(); -``` - -will delete all those users permanently from the table. - -**Querying Soft Deleted Models** - -**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: - -```php -$users = App\Models\User::withTrashed() - ->where('account_type_id', 1) - ->get(); -``` - -The `withTrashed` method may also be used on a [relationship](https://yuga-framework.gitbook.io/documentation/database/elegant/relationships) query: - -```php -$user->posts()->withTrashed()->get(); -``` - -**Retrieving Only Soft Deleted Models** - -The `onlyTrashed` method will retrieve **only** soft deleted models: - -```php -$users = App\Models\User::onlyTrashed() - ->where('account_type_id', 1) - ->get(); -``` - -**Restoring Soft Deleted Models** - -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: - -```php -$users->restore(); -``` - -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: - -```php -$restored = App\Models\User::withTrashed() - ->where('account_type_id', 1) - ->restore(); -``` - -Like the `withTrashed` method, the `restore` method may also be used on [relationships](https://yuga-framework.gitbook.io/documentation/database/elegant/relationships): - -```php -$user->posts()->restore(); -``` - -### Query from Database Views - -Elegant models can not only query from database tables but also from views, see example below: - -```php -$users = App\Models\User::getFromView()->where('active', 1) - ->orderBy('name', 'desc') - ->take(10) - ->get(); -``` - -The above code tells the `elegant service` to query from a view instead of a table, but what view is that exactly?, when the `getFromView` method is given, `Elegant` will look for a view call **`users_view`** from the database and query from that instead of a normal table. -You can customize the `view_name` by providing a `protected` property in your model as below: - -```php -where('active', 1) - ->orderBy('name', 'desc') - ->take(10) - ->get(); -``` - diff --git a/database/elegant/complex-queries.md b/database/elegant/complex-queries.md deleted file mode 100644 index b604f38..0000000 --- a/database/elegant/complex-queries.md +++ /dev/null @@ -1,123 +0,0 @@ ---- -description: >- - Any Query that can be written in a raw form in sql, can also be written in - yuga with the elegant orm. ---- - -# Complex queries - -### Writing Complex database queries with elegant - -You can join tables, query from the same table as many times as you want using only the **`orm`** without having to write a custom query, much as it is possible to write a custom query using the `Elegant ORM`. -The purpose of the `ORM` is to limit if not get rid of custom query use cases, without compromising performance and ease of development. - -An example is: - -```php -$user = new User; -$streams = $user->where('streamable_type', 'user')->whereNotIn('id', function($query) { - $query->from('d_table'); - $query->where('status', '<>', 'A'); - $query->where('userStatus', 'B'); -})->whereIn('id', function ($query) { - $query->where('user_id', 'IN', function($query) { - $query->where('userStatus', '<>', 'B')->select('id'); - }); -})->orWhere('fullname', function($query) { - $query->where('username', 'hsemix'); -})->toSql('raw'); -``` - -The above query would give the following sql: - -```sql -SELECT * FROM `users` -WHERE -`streamable_type` = 'user' AND `id` NOT IN -( - SELECT `user_id` FROM `d_table` WHERE `status` <> 'A' AND `userStatus` = 'B' -) -AND `id` IN -( - SELECT `id` FROM `users` WHERE `userStatus` <> 'B' AND `user_id` IN - ( - SELECT `id` FROM `users` WHERE `userStatus` <> 'B' - ) -) -or `fullname` = -( - SELECT `fullname` FROM `users` WHERE `username` = 'hsemix' -) -``` - -In the above sql, you can clearly see that the results are coming from two tables, i.e; `users and d_table` - -Example 2: - -```php -$user = new User; -$streams = $user->from($user->subQuery($user)) - ->where('streamable_type', 'user') - ->whereNotIn('id', function($query) { - $query->from('d_table'); - $query->where('status', '<>', 'A'); - $query->where('userStatus', 'B'); - })->whereIn('id', function ($query) { - $query->where('user_id', 'IN', function($query) { - $query->where('userStatus', '<>', 'B')->select('id'); - }); - })->orWhere('fullname', function($query) { - $query->where('username', 'hsemix'); - })->toSql('raw'); -``` - -The above would produce the following sql: - -```sql -SELECT * FROM - (SELECT * FROM `users`) -WHERE - `streamable_type` = 'user' -AND - `id` -NOT IN - (SELECT `user_id` FROM - `d_table` - WHERE - `status` <> 'A' - AND - `userStatus` = 'B') - AND - `id` - IN - (SELECT `id` FROM - `users` - WHERE - `userStatus` <> 'B' - AND - `user_id` - IN - (SELECT `id` FROM `users` WHERE `userStatus` <> 'B') - ) - or - `fullname` = - ( - SELECT `fullname` FROM `users` WHERE `username` = 'hsemix' - ) -``` - -Example 3 - -```php -$user = new User; -$query= $user->from($user->subQuery($user)) - ->select($user->subQuery($user, 'user_name')) - ->toSql('raw'); -``` - -Would give the following sql: - -```sql -SELECT (SELECT * FROM `users`) as user_name FROM (SELECT * FROM `users`) -``` - diff --git a/database/elegant/events.md b/database/elegant/events.md deleted file mode 100644 index 77dd94f..0000000 --- a/database/elegant/events.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -description: >- - The Elegant ORM emits events at different intervals whenever something - happens, You just have to hook into them. ---- - -# Events - -### Triggering model events. - -Whenever a model is accessed, whether by querying the database for records or inserting a record or updating a record or even deleting a record, events are triggered, they include: - -* onCreating -* onCreated -* onSaving -* onSaved -* onUpdating -* onUpdated -* onDeleting -* onDeleted -* onSelecting -* onSelected - -Each of the events is a method that you have to implement in your model as follows: - -Let's say that you want to return all **fullnames** in **upper case** of users that exist in the database after you have selected them, this is how you would do it. - -```php -map(function ($user) { - $user->fullname = strtoupper($user->fullname); - return $user; - }); - } -} -``` - diff --git a/database/elegant/relationships.md b/database/elegant/relationships.md deleted file mode 100644 index d14abde..0000000 --- a/database/elegant/relationships.md +++ /dev/null @@ -1,298 +0,0 @@ -# Relationships - -### Defining Relationships - -### \`\`[`One to One`](https://bitbucket.org/hsemix/malibro-yuga/src/aca1c407cde54df3915351418caa26c534c4a7f4/database/elegant/%20https:/yuga-framework.gitbook.io/documentation/database/elegant/relationships#one-to-one)\`\` - -A one-to-one relationship is a very basic relation. For example, a `User` model might be `related` with one `Email`. To define this relationship, we place a `email` method on the `User`model. The `email` method should call the `hasOne` method and return its result: - -{% code title="app/Models/User.php" %} -```php -hasOne(Email::class); - } -} -``` -{% endcode %} - -The first argument passed to the `hasOne` method is the name of the related model. Once the relationship is defined, you can retrieve the related record using Elegant's dynamic properties. Dynamic properties allow you to access relationship methods as if they were properties defined on the model: - -```php -$phone = User::find(1)->email; -``` - -Elegant determines the foreign key of the relationship based on the model name. In this case, the `Email`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: - -```php -return $this->hasOne(Email::class, 'foreign_key'); -``` - -Additionally, Elegant assumes that the foreign key should have a value matching the `id` \(or the custom `$primaryKey`\) column of the parent. In other words, Elegant will look for the value of the user's `id` column in the `user_id` column of the `Email` 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: - -```php -return $this->hasOne(Email::class, 'foreign_key', 'local_key'); -``` - -**Defining The Inverse Of The Relationship** - -So, we can access the `Email` model from our `User`. Now, let's define a relationship on the `Email` 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: - -{% code title="app/Models/Email.php" %} -```php -belongsTo(User::class); - } -} -``` -{% endcode %} - -In the example above, Elegant will try to match the `user_id` from the `Email` model to an `id`on the `User`model. Elegant 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 `Email` model is not `user_id`, you may pass a custom key name as the second argument to the `belongsTo` method: - -```php -/** - * Get the user that owns the email. - */ -public function user() -{ - return $this->belongsTo(User::class, '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: - -```php -/** - * Get the user that owns the email. - */ -public function user() -{ - return $this->belongsTo(User::class, 'foreign_key', 'other_key'); -} -``` - -Note that we have not specified the namespace of the **Email::class**`This is because Elegant tries to resolve model namespaces according to the namespace in which model that has called a relation is. In this case` **`\App\Models.`** `This behaviour can be change ofcourse by passing the fully qualified class name. i.e.` **`\App\MyModels\Email::class`** `or` - -**`'\App\MyModels\Email'`** - -### \`\`[`One to Many`](https://yuga-framework.gitbook.io/documentation/database/elegant/relationships#one-to-many)\`\` - -**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 `Elegant`relationships, one-to-many relationships are defined by placing a function on your Elegant model: - -{% code title="app/Models/Post.php" %} -```php -hasMany(Comment::class); - } -} -``` -{% endcode %} - -Remember, Elegant will automatically determine the proper foreign key column on the `Comment` model. By convention, Elegant will take the "snake case" name of the owning model and suffix it with `_id`. So, for this example, Elegant 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 Elegant provides "dynamic properties", we can access relationship methods as if they were defined as properties on the model: - -```php -$comments = App\Models\Post::find(1)->comments; - -foreach ($comments as $comment) { - //your code -} -``` - -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: - -```php -$comment = App\Models\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: - -```php -return $this->hasMany(Comment::class, 'foreign_key'); - -return $this->hasMany(Comment::class, 'foreign_key', 'local_key'); -``` - -### \`\`[`One to Many Inverse`](https://yuga-framework.gitbook.io/documentation/database/elegant/relationships#one-to-many-inverse)\`\` - -**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: - -{% code title="app/Models/Comment.php" %} -```php -belongsTo(Post::class); - } -} -``` -{% endcode %} - -Once the relationship has been defined, we can retrieve the `Post` model for a `Comment` by accessing the `post` "dynamic property": - -```php -$comment = App\Models\Comment::find(1); - -echo $comment->post->title; -``` - -In the example above, Elegant will try to match the `post_id` from the `Comment` model to an `id` on the `Post` model. Elegant determines the default foreign key name by examining the name of the relationship method and suffixing the method name with a `_` followed by the name of the primary key column. 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: - -```php -/** - * Get the post that owns the comment. - */ -public function post() -{ - return $this->belongsTo(Post::class, '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: - -```php -/** - * Get the post that owns the comment. - */ -public function post() -{ - return $this->belongsTo(Post::class, 'foreign_key', 'other_key'); -} -``` - -### \`\`[`Many to Many`](https://yuga-framework.gitbook.io/documentation/database/elegant/relationships#many-to-many)\`\` - -**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: - -{% code title="app/Models/User.php" %} -```php -belongsToMany(Role::class); - } -} -``` -{% endcode %} - -Once the relationship is defined, you may access the user's roles using the `roles` dynamic property: - -```php -$user = App\Models\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: - -```php -$roles = App\Models\User::find(1)->roles()->orderBy('name')->get(); -``` - -As mentioned previously, to determine the table name of the relationship's joining table, Elegant 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: - -```php -return $this->belongsToMany(Role::class, '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: - -```php -return $this->belongsToMany(Role::class, 'role_user', 'user_id', 'role_id'); -``` - -**Defining The Inverse Of The Relationship** - -To define the inverse of a many-to-many relationship, you 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: - -{% code title="app/Models/Role.php" %} -```php -belongsToMany(User::class); - } -} -``` -{% endcode %} - -As you can see, the relationship is defined exactly the same as its `User` counterpart, with the exception of referencing the `App\Models\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. - -### \`\`[`Polymorphic Relations`](https://yuga-framework.gitbook.io/documentation/database/elegant/relationships#polymorphic-relations)\`\` - diff --git a/database/migrations.md b/database/migrations.md deleted file mode 100644 index 0ce35ad..0000000 --- a/database/migrations.md +++ /dev/null @@ -1,2 +0,0 @@ -# Migrations - diff --git a/database/query.md b/database/query.md deleted file mode 100644 index 94d30f5..0000000 --- a/database/query.md +++ /dev/null @@ -1,215 +0,0 @@ ---- -description: >- - Yuga's database query builder provides a convenient, fluent interface to - creating and running database queries. It can be used to perform all database - operations in your application. ---- - -# Query - -## Retrieving results from the database - -**Retrieving All Rows From A Table** - -You can use the `table` method on the `DB` class to begin a query. The `table` method returns a `\Yuga\Database\Query\DB` 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` or `all` methods: - -```php -get(); - - return view('user.index', ['users' => $users]); - } -} -``` - -The `get / all` methods return a `Yuga\Database\Elegant\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: - -```php -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 can use the `first / last`methods. These methods will return a single `stdClass` object: - -```php -// Retrieve the first record from the collection -$user = DB::table('users')->where('username', 'hamnaj')->first(); - -// Retrive the last record from the collection -$user = DB::table('users')->where('username', 'hamnaj')->last(); - -echo $user->name; -``` - -#### Aggregates - -The query builder also provides a variety of aggregate methods such as `count`, `max`, `min`, `avg`, and `sum`. You can call any of these methods after constructing your query: - -```php -$users = DB::table('users')->count(); - -$price = DB::table('orders')->max('price'); -``` - -You can also combine these methods with other clauses: - -```php -$price = DB::table('orders') - ->where('finalized', 1) - ->average('price'); -``` - -**Simple query**: -Get a user with the id of `3` . Note that `null` is returned when no match is found. - -```php -// This will return a php stdClass object -$users = DB::table('users')->find(3); -``` - -**Full queries**: -Get all users with blue or red hair. - -```php -$users = DB::table('users') - ->where('hair_color', '=', 'blue')) - ->orWhere('hair_color', '=', 'red') - ->get(); -``` - -### Select - -We recommend that you use `table()` method before every `query`, except raw `query()`. -To select from more that one table, pass an array of your tables instead of a plain string. -But this is not a requirement as you can also pass in the different tables as below. - -**Method 1** \(array\) - -```php -$results = DB::table(['users', 'posts']) - ->where('users.post_id', 'posts.id') - ->take(10) - ->get(); -``` - -**Method 2** \(tables as arguments\) - -```php -$results = DB::table('users', 'posts') - ->where('users.post_id', 'posts.id') - ->take(10) - ->get(); -``` - -#### Table alias - -You can easily set the table alias as below: - -```php -$query = DB::table(['users' => 'u']) - ->join('posts', 'posts.user_id', '=', 'u.id'); -``` - -You can change the alias anytime by using: - -```php -$query->alias('uu', 'users'); // uu for users -// or -$query->table('users')->alias('uu'); -``` - -**Output**: - -```sql -SELECT * FROM `users` AS `uu` INNER JOIN `posts` ON `posts`.`user_id` = `uu`.`id` -``` - -#### Multiple selects - -```php -$query = DB::select([ 'mytable.myfield1', 'mytable.myfield2', 'another_table.myfield3' ]); -``` - -**Using select method multiple times** `select('a')->select('b')` will also select **\`a\`** and `b`. This can be useful if you want to do conditional selects \(within a PHP `if`\). - -#### Select distinct - -```php -$query = DB::selectDistinct(['mytable.myfield1', 'mytable.myfield2']); -``` - -#### Select from query - -Items from another query can easily be selected as below: - -```php -$subQuery = DB::table('countries'); - -$query = DB::table(DB::subQuery($subQuery))->where('id', 2); -``` - -Output: - -```sql -SELECT * FROM (SELECT * FROM `countries`) WHERE `id` = 2 -``` - -#### Select single field - -This can be done as below: - -```php -$query = DB::table('users')->select('*'); -// or -$query = DB::table('users')->select('username', 'email'); -// or -$query = DB::table('users')->select(['username', 'email', 'fullname']); -``` - -#### Select with sub-queries - -```php -// first sub-query -$firstSubQuery = DB::table('mails') - ->select(DB::raw('COUNT(*)')); -// send sub-query -$secondSubQuery = DB::table('events')->select(DB::raw('COUNT(*)')); - -// Execute the query - -$count = DB::select( - DB::subQuery($firstSubQuery, 'column1'), - DB::subQuery($secondSubQuery, 'column2') - )->first(); -``` - -Result: - -```sql -SELECT - (SELECT COUNT(*) FROM `mails`) AS column1, - (SELECT COUNT(*) FROM `events`) AS column2 -LIMIT 1 -``` - -You can also easily create a sub-query within the `where` clause as below: - -```php -$query = DB::table('posts') - ->where(DB::subQuery($subQuery), '<>', 'value'); -``` - diff --git a/events/README.md b/events/README.md deleted file mode 100644 index 114e7e0..0000000 --- a/events/README.md +++ /dev/null @@ -1,113 +0,0 @@ ---- -description: Events are a very important aspect of applications nowadays. ---- - -# Events - -In a typical **yuga** application, events are triggered almost everywhere in the entire application, i.e, when someone `loads` your application, the `on:start` event is triggered, when someone `queries` the database, the `on:query` event is triggered, when someone `logs in`to your application, the `on:authenticate` event is triggered, when someone `logs out`, the `on:logout` event is triggered. -All the mentioned events are **built-in events** that come with yuga, of course someone can define their own events and trigger them any where in the application - -The idea behind events is the ability to send data, as parameters, to handlers and call them when an event happens. The handlers could be a closure or a static class method, or even an instance object method. - -### Registering Events & Handlers - -All application events in a typical **yuga** application live in `config/AppEvents.php` file, which returns an array of events and their handlers or listeners. - -This is the format of registering the events and binding them to their respective handlers or listeners for that matter; - -```php - App\Handlers\EventHandler::class || [EventHandlerClass1::class, EventHandlerClass2::class] - * OR - * 'eventname' => '\App\Handlers\EventHandler' - */ -return [ - 'on:authenticate' => [ - App\Handlers\UserAuthenticated::class, - App\Handlers\LogToFile::class, - ], -]; - -// you can also use the following format for a single handler per event -return [ - 'on:authenticate' => \App\Handlers\UserAuthenticated::class, - 'onTest' => [ - ['\App\Handlers\UserAuthenticated', 'onTest'] - ], -]; - -// For any other method in the handler class other than the handle method -return [ - 'on:authenticate' => [ - ['\App\Handlers\UserAuthenticated', 'onLogin'] - ], - 'onTest' => [ - ['\App\Handlers\UserAuthenticated', 'onTest'], - ['\App\Handlers\UserTesting', 'whenSuccessful'] - ], -]; -``` - -### Dispatching Events - - To dispatch an event, you may pass an instance of the event to the `event` helper function. The helper function will dispatch the event to all of its registered handlers. Since the `event` helper function is globally available, you may call it from anywhere in your application: - -```php -trigger(new TestEvent($user)); // u can also use the dispatch(event) method - // or if the event-name is on:test - $event->trigger('on:test', compact('user')); // u can also use the dispatch(event) method - } -} -``` - diff --git a/events/event-classes.md b/events/event-classes.md deleted file mode 100644 index 4882e46..0000000 --- a/events/event-classes.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -description: >- - An event class is a data container which holds the information related to the - event. ---- - -# Event Classes - -### Defining Events - - For example, let's assume our generated `UserAuthenticated` event is to be defined and will transport an Elegant `Model` or a `collection` of `Elegant` Models to its handlers; - -```php -- - Event handlers are classes that carry the logic of the events defined in - previous sections ---- - -# Event Handlers - -### Defining Handlers - -```php - The `--method` flag in the above comment is optional, and if not provided, the handler will register with the `handle` method. -> -> Even the `--event` is also optional but we strongly advise to always provide it, because when it's not provided, **yuga-auto-events** will be the registered event - -{% hint style="info" %} -If the provided event name is a valid php class, the class will be injected in the event method provided as below. -{% endhint %} - -For the following command - -```bash -php yuga event:handler WhenAuthenticated --event=UserAuthenticated --method=i -sAuthentic -``` - -```php -app = $app; - } - - /** - * Handle an incoming request. - * - * @param \Yuga\Http\Request $request - * @param \Closure $next - * @return mixed - */ - public function run(Request $request, Closure $next) - { - // Write you code for checking if the user's role is admin here - if (!Auth::user()->isAdmin()) { - return redirect('home'); - } - return $next($request); - } -} -``` - -#### Assigning Middleware To Routes - -If you would like to assign middleware to specific routes, you should first assign the middleware a key in your `config/AppMiddleware` file. By default, the file comes with an array with only one middleware that comes with yuga, feel free to add as many as you want. - -You can avoid this by using the command `php yuga make:middleware TestMiddleware` and yuga will make `TestMiddleware` lower cased without the word middleware and will push it to `config/AppMiddleware` array for you. - -```php -// Within config/AppMiddleware.php - -return [ - 'guest' => \App\Middleware\RedirectIfAuthenticated::class, -]; -``` - -Once the middleware has been defined in the config/AppMiddleware array, you can use it on a given route as below: - -```php -// Single middleware -Route::get('/users', ['middleware' => 'test', 'UsersController']); -// An array of middleware -Route::get('/users', [ - 'middleware' => [ - 'middleware1', - 'middleware2', - ], - 'UsersController' -]); - -// Middleware on a group of routes - -Route::group(['middleware' => 'auth'], function () { - Route::get('/', function () { - // Uses Auth Middleware - }); - - Route::get('/user/profile', function () { - // Uses Auth Middleware - }); -}); -``` - diff --git a/queue-worker.md b/queue-worker.md deleted file mode 100644 index 2c45df9..0000000 --- a/queue-worker.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -description: Queue workers ---- - -# Queue worker - diff --git a/schedulers.md b/schedulers.md deleted file mode 100644 index 6d1eae8..0000000 --- a/schedulers.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -description: Schedulers ---- - -# Schedulers - -This makes scheduling cronjobs in your application simple, flexible, and powerful. Instead of setting up multiple cronjobs on each server your application runs on, you only need to set up a single cronjob to point to the script, and then all of your tasks are scheduled in your code. Besides that, it provides CLI tools to help you manage the tasks that should be run. - -Instead of what used to be done in the past of generating a Cron entry for each task you needed to schedule on your server. This is hard to manage since your task schedule is no longer in source control and you must SSH into your server to add additional Cron entries. diff --git a/service-providers.md b/service-providers.md deleted file mode 100644 index b107a34..0000000 --- a/service-providers.md +++ /dev/null @@ -1,118 +0,0 @@ ---- -description: >- - Service providers are the central place for all Yuga application service - registering. ---- - -# Service Providers - -Your own application, as well as all of Yuga's core services are registered via service providers. These include: - -* Elegant Database -* View -* Validation -* Session -* Events -* Router -* Console Application, to name but a few. - - Registered Service Providers are found in `config/ServiceProviders.php` When the file is opened, you will see an array returned from that file which array contains all the registered `service providers`, When you create a service provider using a `yuga command`, this is where it's registered, you can also insert it there by hand if you will. - -### [Creating Service Providers](https://yuga-framework.gitbook.io/documentation/service-providers#creating-service-providers) - -All service providers extend the `Yuga\Providers\ServiceProvider` class and they all contain a `load` method, other methods may be introduce in future and we'll let you know. Use the `load` method to bind everything you want to use in your application. - -The Yuga command used to generate a service provider is as below: - -```text -php yuga make:provider LogServiceProvider -``` - -#### [The Load Method](https://yuga-framework.gitbook.io/documentation/service-providers#the-load-method) - -It's within the `load` method that things are bound to your application, "things" in this case could mean classes that you want your application to have on every single request or strings, it could pretty much be anything. - -The following code represents a basic service provider and how the `load` method must be used. All services are bound to the `$app` variable provided as an argument to the `load` method as below: - -```php -singleton('my-users', function ($app) { - return User::all(); - }); - } -} -``` - -#### [Using Service Providers](https://yuga-framework.gitbook.io/documentation/service-providers#using-service-providers) - -Inside of your `controllers` or `view-models`, you can get the service that has been already registered in the following way: - -```php -make('my-users'); - - // or - - $users = $app['my-users']; - } -} -``` - -```php -make('my-users'); - - // or - - $users = app()['my-users'); - } -} -``` - - - diff --git a/view-models.md b/view-models.md deleted file mode 100644 index caf7e7b..0000000 --- a/view-models.md +++ /dev/null @@ -1,421 +0,0 @@ ---- -description: >- - A Yuga ViewModel is a special class that represents the data model used in a - specific view. ---- - -# ViewModels - -### What is a ViewModel?, What makes it different from a controller? - -In a `yuga` application, every view has a `code behind file`which in this case is our view model, `View models` can work as `controllers` but the main difference lies in how they couple with views, a `controller` can return any view and it doesn't interact with the view itself while a `view model` interacts directly with the view and returns only that view. In fact, you don't tell it the view it has to return, It already knows it. - -A view model in a yuga application binds a form to a real database `model` such that the developer doesn't need to do the mapping of form fields to a model them selves. - -It has `automatic validation` of form fields. This can turn out to be a time saver, if custom validation is needed, a `validate` method is provided to a model to which the view model is bound and the view model will run that method instead of the default. - -> While you can do pretty much everything from within a controller, a view model simplifies your work by taking away tasks like `validation` and `form-model` binding. - -### Basic ViewModels - -#### Defining ViewModels - -Below is an example of a basic ViewModel class. Note that the ViewModel extends the base ViewModel class that comes with Yuga. The base class provides a few convenience methods such as the `onPost, onLoad, onGet` methods, which can be used whenever those events occur. - -{% tabs %} -{% tab title="app/ViewModels/UserViewModel.php" %} -```php -namespace App\ViewModels; - -class UserViewModel extends App -{ - /** - * Create a new UserViewModel ViewModel instance. - * - * @return void - */ - public function __construct() - { - parent::__construct(); - } - - /** - * Handle any form data that has been submited - */ - public function onPost($model) - { - - } - - /** - * Load or / manupulate data when its a get request - */ - public function onGet() - { - - } - - /** - * Load or / manupulate data before the page loads and feed it to the page - */ - public function onLoad() - { - - } -} -``` -{% endtab %} -{% endtabs %} - -What's in the App class that the above class is extending? Let's find out - -{% tabs %} -{% tab title="app/ViewModels/App.php" %} -```php -namespace App\ViewModels; - -use Yuga\View\ViewModel; -use Yuga\Views\Widgets\Menu\Menu; - -abstract class App extends ViewModel -{ - protected $applicationMenu; - public function __construct() - { - parent::__construct(); - $this->name = 'Yuga Framework'; - $this->getSite()->setTitle('Welcom to ' . $this->name) - ->addCss(assets('yuga/bootstrap/css/bootstrap.min.css')) - ->addCss(assets('yuga/css/yuga.css')) - ->addJs(assets('yuga/js/jQuery/jquery-2.2.3.min.js')) - ->addJs(assets('yuga/bootstrap/js/bootstrap.min.js')) - ->addJs(assets('yuga/js/yuga.client.js')); - $this->makeMenu(); - } - - protected function makeMenu() - { - $this->applicationMenu = new Menu; - $this->applicationMenu->addClass('nav navbar-nav'); - if (\Auth::authRoutesExist()) { - if (\Auth::guest()) { - $this->applicationMenu->addItem('Login', route('login'))->addClass('nav-item')->addLinkAttribute('class', 'nav-link'); - $this->applicationMenu->addItem('Register', route('register'))->addClass('nav-item')->addLinkAttribute('class', 'nav-link'); - } else { - $this->applicationMenu->addItem('Logout', route('/logout'))->addClass('nav-item')->addLinkAttribute('class', 'nav-link'); - } - } - } - protected function printMenu() - { - return $this->applicationMenu; - } -} - -``` -{% endtab %} -{% endtabs %} - -The route that corresponds to this `UserViewModel` is as below: - -{% tabs %} -{% tab title="routes/web.php" %} -```php -Route::get('add-users', App\ViewModels\UserViewModel::class); -``` -{% endtab %} -{% endtabs %} - -#### [Dependency Injection & ViewModels](http://yuga-framework.gitbook.io/documentation/view-models) - -**Constructor Injection** - -The Yuga [service container](https://yuga-framework.gitbook.io/documentation/providers) is used to resolve all Yuga ViewModels. As a result, you are able to type-hint any dependencies your ViewModel may need in its constructor. The declared dependencies will automatically be resolved and injected into the ViewModel instance: - -{% tabs %} -{% tab title="app/ViewModels/UserViewModel.php" %} -```php -namespace App\ViewModels; - -use App\Models\User; - -class UserViewModel extends App -{ - /** - * The user model instance. - */ - protected $user; - - /** - * Create a new UserViewModel ViewModel instance. - * - * @param User $user - * @return void - */ - public function __construct(User $user) - { - $this->user = $user; - } -} -``` -{% endtab %} -{% endtabs %} - -**Creating ViewModels using yuga console command** - -ViewModels can be created using the `php yuga make:viewmodel` command - -i.e `php yuga make:viewmodel UserViewModel` would produce the following scaffold: - -{% tabs %} -{% tab title="app/ViewModels/UserViewModel.php" %} -```php -namespace App\ViewModels; - -class UserViewModel extends App -{ - /** - * Create a new UserViewModel ViewModel instance. - * - * @return void - */ - public function __construct() - { - parent::__construct(); - } - - /** - * Handle any form data that has been submited - */ - public function onPost() - { - - } - - /** - * Load or / manupulate data when its a get request - */ - public function onGet() - { - - } - - /** - * Load or / manupulate data before the page loads and feed it to the page - */ - public function onLoad() - { - - } -} -``` -{% endtab %} -{% endtabs %} - -## Model binding to the **ViewModel** - -Think of this as an easier way of mapping every form value to an appropriate Object attribute or property. In **`yuga`**, this works like magic. - When a form is submitted, the **`ViewModel`** looks for the bound Model from the scope and maps every form field to a property on that **`Model`** and finally tries to run a `validator` to every field on the form to make sure that every form field is not empty for starters. - -The default bound model is `\Yuga\Models\ElegantModel::class` But of course the table that is bound to this model is `elegant_models` which basically doesn't make any sense for every form, so how do we bind a model to a form, Well, there're two ways of doing this, - -* You may skip binding to the form yourself and instead set a table to be bound to the `ElegantModel` class, this is done as below: `$this->setTable("my_table");` inside of the view-model's constructor. -* Or you can bind any other model you would like to use instead of `ElegantModel` as below: - -```php -setModel(['form' => new App\Models\User]); - } -} -``` - -### Basic Structure - -When a form is submitted and it is a post request method, the **`onPost`** method is run and so this is where your code for form manipulation should reside. - -Example of a view \(`My.php`\) - -{% tabs %} -{% tab title="My.php" %} -```php -
This is appended to the master nav-bar.
-@endsection - -@section('main') -This is my body content.
-@endsection -``` - -### [Displaying Data](https://yuga-framework.gitbook.io/documentation/views/mvc/hax-templates#displaying-data) - -You can display data passed to your Hax views by wrapping the variable in curly braces. For example, given the following route: - -```php -Route::get('hello', function () { - return view('details', ['name' => 'John Doe']); -}); -``` - -You can display the contents of the `name` variable like below: - -```php -Hello, {{ $name }}. -``` - -### [Control Structures](https://yuga-framework.gitbook.io/documentation/views/mvc/hax-templates#control-structures) - -In addition to template inheritance and displaying data, Hax also provides convenient shortcuts for common PHP control structures, such as conditional statements and loops. - -#### [If Statements](https://yuga-framework.gitbook.io/documentation/views/mvc/hax-templates#if-statements) - -You may construct `if` statements using the `@if`, `@elseif`, `@else`, and `@endif` directives. These directives function identically to their PHP counterparts: - -```php -@if (count($items) === 1) - You have one item! -@elseif (count($items) > 1) - You have multiple items! -@else - You don't have any items! -@endif -``` - -#### [Loops](https://yuga-framework.gitbook.io/documentation/views/mvc/hax-templates#loops) - -In addition to conditional statements, Hax provides simple directives for working with PHP's loop structures. Each of these directives functions identically to their PHP counterparts: - -```php -@for ($i = 0; $i < 10; $i++) - The index is {{ $i }} -@endfor - -@foreach ($users as $user) -This is user {{ $user->id }}
-@endforeach - -@forelse ($users as $user) -This loop will run forever.
-@endwhile -``` - diff --git a/views/mvvm.md b/views/mvvm.md deleted file mode 100644 index c0b1fce..0000000 --- a/views/mvvm.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -description: Views in this pattern are basically the front-end of your ViewModels logic ---- - -# MVVM - -Views contain the HTML served by your application and separate your ViewModel code-behind logic from your presentation logic. Views are saved in the `resources/views/templates` directory. A simple view would look like this: - -```php -