From f2f4bc0c7a1fc41dbbd0627b901f7687e80f67a5 Mon Sep 17 00:00:00 2001 From: Terzi Eduard Date: Sun, 6 Oct 2019 20:18:12 +0300 Subject: [PATCH 1/2] Update docs --- docs/Customization/dashboard.md | 15 ++- docs/Customization/navigation.md | 44 ++++---- docs/Features/media.md | 2 +- docs/Forms/forms.md | 103 +++++------------- docs/Forms/savers.md | 9 +- docs/GettingStarted/configuration.md | 12 +-- docs/GettingStarted/installation.md | 41 ++++---- docs/Listing/actions.md | 149 +++------------------------ docs/Listing/filters.md | 112 +++++++++----------- docs/Listing/grid.md | 43 +++----- 10 files changed, 164 insertions(+), 366 deletions(-) diff --git a/docs/Customization/dashboard.md b/docs/Customization/dashboard.md index 836dbf7..276fa11 100644 --- a/docs/Customization/dashboard.md +++ b/docs/Customization/dashboard.md @@ -5,8 +5,6 @@ Dashboard probably is the most-visited by administrators page of every admin panel! And Admin Architect doesn't want to be an exception. -The main dashboard template is located at `resources/views/vendor/administrator/layouts/dashboard.blade.php` - You decide the number of widgets, their position and their content... It may be a simple Counter or a complex Graph - it doesn't mater... @@ -17,7 +15,7 @@ Admin Architect provides an easy way to add new widget: php artisan administrator:panel Overview ``` -Where the `Overview` panel is a simple class that implements `Widgetable` contract with the single method `render()`: +Where the `Overview` panel is a simple class that implements `Terranet\Administrator\Dashboard\Panel` contract with the single required method `render()`: ```php class Overview implements Widgetable @@ -93,19 +91,18 @@ class Registrations implements Widgetable One thing you need to do, is to register your dashboard panel in Dashboard factory: ```php -### \App\Http\Terranet\Administrator\Dashboard\Factory -protected function registerPanels() +### App\Providers\AdminServiceProvider +protected function dashboard(Manager $dashboard) { - $this->dashboard + return $dashboard ->row(function (Row $row) { # consider Bootstrap 12 columns grid $row->panel(new Overview)->setWidth(12); }) ->row(function(Row $row) { - $row->panel(new Registration)->setWidth(12); + $row->panel(new Registrations)->setWidth(6); + $row->panel(new ReturningVisitors)->setWidth(6); }); - - return $this->dashboard; } ``` diff --git a/docs/Customization/navigation.md b/docs/Customization/navigation.md index e39284b..ca4248d 100755 --- a/docs/Customization/navigation.md +++ b/docs/Customization/navigation.md @@ -1,6 +1,6 @@ ## Navigation -By default any new resource is auto Navigable. +By default any new resource is auto `Navigable`. To change the way how it appears in the navigation there is a set of methods provided out of the box, like: @@ -95,42 +95,40 @@ To disable the resource from being displayed in the global navigation just don't For more details about how to customize the resource appearance in the navigation please checkout the [Resources Navigation](http://docs.adminarchitect.com/Resources) documentation section. -To change default navigation structure, checkout `App\Http\Terranet\Administrator\Navigation` class. +To change default navigation structure, checkout `App\Providers\AdminServiceProvider::navigation` method. There is a navigation skeleton you might customise for your needs: ```php -protected function makeSidebar() +protected function initSidebar(Menu $navigation): self { - $this->navigation->create(Navigable::MENU_SIDEBAR, function (MenuBuilder $sidebar) { - // Dashboard - $sidebar->route('scaffold.dashboard', trans('administrator::module.dashboard'), [], 1, [ - 'id' => 'dashboard', - 'icon' => 'fa fa-dashboard', - ]); - - // Create new users group - $sidebar->dropdown(trans('administrator::module.groups.users'), function (MenuItem $sub) { - if (auth('admin')->user()->canAdmin('admin.users.create')) { - $sub->route( - 'scaffold.create', - trans('administrator::buttons.create_item', ['resource' => 'User']), - ['module' => 'users'], 1, [] - ); - } - }, 2, ['id' => 'groups', 'icon' => 'fa fa-group']); + $navigation->create(Navigable::MENU_SIDEBAR, function (MenuBuilder $sidebar) { + $this->withDashboard($sidebar); + + // Create "resources" group + $sidebar->dropdown(trans('administrator::module.groups.resources'), static function (MenuItem $sub) { + // $sub->route(); + }, 2, ['id' => 'groups', 'icon' => 'fa fa-qrcode']); }); + + return $this; } -protected function makeTools() +protected function initToolbar(Menu $navigation): self { - $this->navigation->create(Navigable::MENU_TOOLS, function (MenuBuilder $tools) { + $navigation->create(Navigable::MENU_TOOLS, function (MenuBuilder $tools) { + $this->withMedia($tools) + ->withSettings($tools) + ->withTranslations($tools); + $tools->url( route('scaffold.logout'), trans('administrator::buttons.logout'), 100, - ['icon' => 'glyphicon glyphicon-log-out'] + ['icon' => 'fa fa-mail-forward'] ); }); + + return $this; } ``` \ No newline at end of file diff --git a/docs/Features/media.md b/docs/Features/media.md index a6d4b2a..df32123 100755 --- a/docs/Features/media.md +++ b/docs/Features/media.md @@ -1,4 +1,4 @@ -## File Manager +## File Manager (Experimental) ![Admin Architect - Media](http://docs.adminarchitect.com/images/plugins/media.png) diff --git a/docs/Forms/forms.md b/docs/Forms/forms.md index e289e86..fc21e1c 100755 --- a/docs/Forms/forms.md +++ b/docs/Forms/forms.md @@ -10,76 +10,25 @@ You can extend default form by adding columns or changing the column settings: For models, each field should be one of your model's SQL columns or one of its Eloquent relationships or any custom field (assuming you define the mechanism to handle and save it). -``` +```php public function form() { - return $this - ->scaffoldForm() - - # Update existing column - ->update('user_id', function ($element) { - # Set a different input type - $element->setInput( - new Select('user_id') - ); - - # set dropdown options - $element->getInput()->setOptions( - User::pluck('name', 'id')->toArray() - ); - - return $element; - }) - - # add a new Relation meta.keywords - ->create('meta.keywords', 'text') - - # add another Relation meta.description - ->create( - FormElement::textarea('meta.description'), - function ($description) { - # Like titles, hints translations are auto-discovered by - # asking Translator for keys: - # 1. administrator::hints.. - # 2. administrator::hints.global. - $element->setDescription('Element description'); - - return $description->setTitle('Meta description'); - } - ); + return $this->scaffoldForm() + ->update('description', function (TranslatableField $field) { + return $field->tinymce(); + }) + ->push(CustomField::make('custom_view')) + ->push(HasOne::make('Place Details', 'details')) + ->push(BelongsTo::make('Belongs to City', 'city')->searchable(false)) + ->push(BelongsToMany::make('Belongs to Tags', 'tags')->tagList()) + ; } ``` -`.dot` notation points to a relationship, -in case of `meta.` - it points to a HasOne relationship `Post::meta()`, - += ### Supported form controls -The complete list (updates constantly) of supported controls: - - * @method static FormElement text(string $name) - * @method static FormElement view(string $name) - * @method static FormElement search(string $name) - * @method static FormElement textarea(string $name) - * @method static FormElement medium(string $name) - * @method static FormElement tinymce(string $name) - * @method static FormElement ckeditor(string $name) - * @method static FormElement boolean(string $name) - * @method static FormElement radio(string $name, array $attributes, array $options) - * @method static FormElement multiCheckbox(string $name, array $attributes = [], array $options = []) - * @method static FormElement datalist(string $name, array $attributes = [], array $options = []) - * @method static FormElement date(string $name) - * @method static FormElement daterange(string $name) - * @method static FormElement datetime(string $name) - * @method static FormElement time(string $name) - * @method static FormElement email(string $name) - * @method static FormElement file(string $name) - * @method static FormElement hidden(string $name) - * @method static FormElement image(string $name) - * @method static FormElement key(string $name) - * @method static FormElement markdown(string $name) - * @method static FormElement number(string $name) - * @method static FormElement password(string $name) - * @method static FormElement select(string $name, array $attributes, array $options) - * @method static FormElement tel(string $name) + +For complete list of supported fields please review the `Terranet\Administrator\Field` directory: + ### Files & Images Files & Images are handled by `czim/laravel-paperclip` library. @@ -130,18 +79,20 @@ Then in your resource you can call method `media` to add a `media` control to ed ```php # Ex.: app/Http/Terranet/Administrator/Modules/Users.php -public function form() +// if you want to view the status on index page +public function columns(): Mutable { - return $this->scaffoldForm() - ->media('galaxy', function (FormElement $element) { - /** @var $media MediaElement */ - $media = $element->getInput(); - $media->hasArrows(true) # [optional] if it should have navigation arrows - ->hasIndicators(true) # [optional] if it should have navigation bullets - ->convertedTo('thumbnail') # [optional] show specific conversion - ->autoPlay(2) # [optional] set auto play duration (sec) - doesn't work for forms (only in columns) - ->maxWidth(200); # [optional] set max width - }); + return $this->scaffoldColumns() + ->push(Media::make('images')) + ; +} + +// to allow adding media files on Item Detail page +public function viewColumns(): Mutable +{ + return $this->scaffoldColumns() + ->push(Media::make('images')) + ; } ``` diff --git a/docs/Forms/savers.md b/docs/Forms/savers.md index 5af716e..f5f34b0 100755 --- a/docs/Forms/savers.md +++ b/docs/Forms/savers.md @@ -1,13 +1,14 @@ -## Savers +# Savers Admin Architect does a huge work to persist your model, presented by a Form. -It also handles Images, Files, RelationShips, etc... + +It also handles Images, Files, RelationShips, Translations, Media, etc... But somethimes it is not enough, you need a way to store your form data differently. For these cases we provide a Resource-dedicated service called: `Saver` -### Create saver +## Create saver Let's store our users differently @@ -20,7 +21,7 @@ There is one single public method `sync()` and a bunch of protected methods you Let's say, we need to create a log record, once a User were saved: -Note! Yes, we know, there is a better way to do it (using events, etc...), but just for a demonstration purpose, let's do it here... +Note! Yes, we know, there is a better way to do it (using events, queued jobs, etc...), but just for a demonstration purpose, let's do it this way... ```php public function sync() diff --git a/docs/GettingStarted/configuration.md b/docs/GettingStarted/configuration.md index 0885a70..3a3474c 100644 --- a/docs/GettingStarted/configuration.md +++ b/docs/GettingStarted/configuration.md @@ -71,13 +71,7 @@ If you find this feature unnecessary - just set it to `false`. ``` Enable File Manager by setting its option to `true`; -#### Factories -There are few factories (containers) you might be interested in. +#### Service Provider -```php -# Navigation factory -'menu' => \Terranet\Administrator\Navigation\Factory::class, - -# Dashboard panels factory -'dashboard' => \App\Http\Terranet\Administrator\Dashboard\Factory::class, -``` \ No newline at end of file +AdminArchitect will publish its own service provide into `App\Providers\AdminServiceProvider`. +By default it contains the routing & navigation registrations. \ No newline at end of file diff --git a/docs/GettingStarted/installation.md b/docs/GettingStarted/installation.md index d31c5fa..8399bf0 100644 --- a/docs/GettingStarted/installation.md +++ b/docs/GettingStarted/installation.md @@ -1,4 +1,4 @@ -## Installation +# Installation As you always do, install composer package: @@ -6,8 +6,8 @@ As you always do, install composer package: composer require adminarchitect/core ``` -### Registering -_[Skip for Laravel 5.5]_ +## Registering +_[Skip for Laravel 5.5+]_ Once the package installed, register its service provider in config/app.php file. @@ -18,48 +18,45 @@ Once the package installed, register its service provider in config/app.php file ... ] ``` -### Publishing + +## Publishing Publish package's assets, translation and configuration by running: ```bash php artisan administrator:publish ``` + Answer few questions about configuration steps. -It will copy adminarchitect's assets to a resources/assets/administrator directory. -All views will be copied to a resources/views/vendor/administrator directory. +It will copy adminarchitect's assets to a `/administrator-mix` directory. +Views & translations files will be copied to a corresponding locations: `resources/{views,lang}/vendor/administrator` directories. -### Assets -AdminArchitect assets are provided in ES6 and less/sass formats, so to convert them to a js/css there is a NPM package `@adminarchitect/mix`. +## Assets +AdminArchitect assets are provided in ES6 and less/sass formats, so to convert them to a js/css, enter the `adminarchitect-mix` directory and run: ```bash -yarn -D @adminarchitect/mix -OR -mpm i @adminarchitect/mix --save-dev +npm i +mpm run [dev|production|watch] ``` -Next step is to register AdminMix tasks, so add these lines to your `webpack.mix.js`: +## Editors -```js -const AdminMix = require('@adminarchitect/mix'); -(new AdminMix).handle(); -``` +AdminArchitect comes with 4 visual editors: TinyMce, CkEditor, Medium & Markdown. +In order to connect editor of your choice - follow the instructions from `adminarchitect-mix/webpack.mix.js` file. then you can run any of these commands, to build assets: -```bash -yarn run [dev|production|watch] -``` All generated assets will be placed to `public/admin` directory. -### Migrations +## Migrations + if you're running a fresh Laravel installation, run: ```bash php artisan migrate ``` -### Create administrator +## Create administrator Now let's create a new administrator account: @@ -67,7 +64,7 @@ Now let's create a new administrator account: php artisan administrator:create ``` -### Enjoy +## Enjoy Now you can access the Admin Architect by opening a `/cms` url. So for `php artisan serve` command, it will: [http://localhost:8000/cms](http://localhost:8000/cms) \ No newline at end of file diff --git a/docs/Listing/actions.md b/docs/Listing/actions.md index eade725..6d4c6e8 100644 --- a/docs/Listing/actions.md +++ b/docs/Listing/actions.md @@ -1,4 +1,4 @@ -## Actions +# Actions Admin Architect provides 2 action types: - Single (applied to every single element in a collection) @@ -6,11 +6,11 @@ Admin Architect provides 2 action types: To understand better, here are some examples: * Edit/Delete/View - are examples of single actions. -* Check More && Delete Selected Items - is a batch action. +* Check All && Delete Selected Items - is a batch action. * * * -### Single (Row-Based) Actions +## Single (Row-Based) Actions ![Admin Architect - Single actions](http://docs.adminarchitect.com/images/index/single_actions.jpg) @@ -22,158 +22,43 @@ Sometimes you'll need to have something more then just CRUD actions, or maybe yo For instance: maybe you'll wish to `activate` or `lock` specific users, view project reports, report emails as spam, etc... -Admin Architect gives you ability to create the action containers (collections) which receive as a callback parameter selected model, at this moment you are free to use the model in the way you need. +Admin Architect gives you ability to create the action containers which receive as a callback parameter selected model, at this moment you are free to use the model in the way you need. -### CRUD Authorisation +## CRUD Authorisation Admin Architect provides a simple way to organize authorization logic and control access to resources. We'll review few use cases of how you can organize your Authorization logic. -#### Abilities +### Abilities -The very first way to determine if a user may perform a given CRUD action is to define an "ability" declaring the `can` method. +AdminArchitect is fully compatible with Laravel's Policy. -Within our `abilities`, we will determine if the logged in user has the ability to delete, update, view post: +So in order to control the ability to list (index), view, create, update or delete - define the corresponding method in your Policy Class. For this purpose we'll need to have the these `abilities` defined in our `Actions` service (See [Create Actions](/Listing/actions?id=create-actions) section). ```php -# Actions\Posts::class +# App\Policy\Post::class -/** - * @param $user - Logged in user - * @param $entity - Eloquent model you're going to Delete/Update/View/etc... - */ -public function canDelete($user, $entity) +public function delete($user, $entity) { return $user->isSuperAdmin() || $user->isOwnerOf($entity); } -public function canUpdate($user, $entity) +public function update($user, $entity) { - return $this->canDelete($user, $entity); + return $this->delete($user, $entity); } -public function canView($user, $entity) +public function view($user, $entity) { - return $this->canDelete($user, $entity); + return $this->delete($user, $entity); } ``` -#### ACL Manager +*Note!* If you do not define a policy method - AdminArchitect will consider the permission as enabled, it means if you do not have the `delete` method defined in model's policy class - logged user will be able to delete any corresponding record. -The second and more general & powerful method is to create a `GuardManager` class and register it in the `config/administrator.php`... - -Let's see an example: - -```php -# administrator.php -'acl' => [ - 'manager' => \App\Services\GuardManager::class, -], -``` - -```php -# App\Services\GuardManager.php - -namespace App\Services; - -use Illuminate\Contracts\Auth\Authenticatable; -use Terranet\Administrator\Scaffolding; - -class GuardManager -{ - protected $module = null; - - public function __construct(Scaffolding $module) - { - $this->module = $module; - } - - public function canCreate(Authenticatable $user) - { - return $user->can( - $this->permission('create') - ); - } - - public function canUpdate(Authenticatable $user, $eloquent) - { - return $user->can( - $this->permission('update'), - $eloquent - ); - } - - public function canDelete(Authenticatable $user, $eloquent) - { - return $user->can( - $this->permission('delete'), - $eloquent - ); - } - - public function canView(Authenticatable $user, $eloquent) - { - return in_array($this->module->url(), ['users', 'offers']); - } - - public function canIndex(Authenticatable $user) - { - return $user->can( - $this->permission('index') - ); - } - - public function showIf() - { - return $this->canIndex( - $this->user() - ); - } - - protected function user(): Authenticatable - { - return auth('admin')->user(); - } - - protected function permission($permission) - { - return $this->module->url() . '.' . $permission; - } -} - -# Authenticable::can() method can realize any logic inside, it can have the `zizaco/entrust` logic or something similar or more complex, it just must return true or false (does user can perform the action or not). -# $permission - string representation of ., like: users.index, users.create, users.edit -# it also receives a current $eloquent model as a second argument. -``` - -#### Alternative way - -As an alternative way, to enable/disable CRUD action in a global aspect, there is a simple tricky way: -open your `AppServiceProvider` and add this to `boot()` method: - -```php -# available CRUD actions: canView, canDelete, canUpdate, canCreate -Scaffolding::addMethod('canView', function ($user, $eloquent) { - # let's enable View action for Users module - if (in_array(app('scaffold.module')->url(), ['users'])) { - return true; - } - - # and disable for others - return false; -}); - -# Ex.: Only Admins and Managers are able to Update some row. -# @param $user - logged in user -# @param $eloquent - the model you try to update -Scaffolding::addMethod('canUpdate', function($user, $eloquent) { - return $user->hasRole(['admin', 'manager']); -}); -``` - -### Create Actions +## Create Actions As we said you can add your own actions, for this you have to create a `Actions Container`: @@ -260,7 +145,7 @@ class ToggleActiveStatus } ``` -### Batch Actions +## Batch Actions ![Admin Architect - Batch actions](http://docs.adminarchitect.com/images/index/batch_actions.jpg) diff --git a/docs/Listing/filters.md b/docs/Listing/filters.md index 7c4f944..8fe86fa 100644 --- a/docs/Listing/filters.md +++ b/docs/Listing/filters.md @@ -2,7 +2,7 @@ Filtering and listing resources is one of the most important tasks for administering a web application. -All of Admin Architect resources out of the box does support scopes & filters. +All AdminArchitect resources out of the box does support scopes & filters. Admin Architect provides a set of default tools for you to build a compelling interface into your data for the admin staff. @@ -27,95 +27,83 @@ public function filters() ->scaffoldFilters() # optionaly remove unnecessary - ->without(['column 1', 'column x']) + ->except(['column 1', 'column x']) # let's filter our collection by user_id column ->push( - FilterElement::select('user_id', [], $this->users()) + Enum::select('user_id', [], ['' => '--Any--'] + User::pluck('name', 'id')) ) # optionaly for foreign columns (not existing in database, aggregated or joined, etc...) # we can define a custom query - ->update('phone', function ($control) { - $control->getInput() - # when called, function will receive 2 arguments - # 1. original query - # 2. requested value - ->setQuery(function ($query, $value) { - # created in Finder::getQuery() - return $query - ->join('user_profile as p', 'p.user_id', '=', 'users.id') - ->where('p.phone', $value); - }); - - return $control; - }); -} - -protected function users() -{ - return ['' => '--Any--'] + User::pluck('name', 'id')->toArray(); + ->push(Text::make('Phone')->setQuery(function (Builder $builder, $value) { + return $builder + ->join('place_details as pd', 'pd.place_id', '=', 'places.id') + ->where('phone', $value); + })); } ``` -Supported filter HTML types: -`text`, `select`, `datalist`, `date`, `daterange`, `search`, `number`. +Supported filters can be found in `Terranet\Administrator\Filter` location: -As you might see, for complex filters that require more control while fetching resources, you are able to define an optional \Closure $query attribute via setQuery() method. +As you might see, for complex filters that require more control while fetching resources, you are able to define an optional `\Closure` $query attribute via `setQuery()` method. To disable filters for specific resource - remove Filtrable interface from Resource's `implements` section or just return an empty collection: -### Scopes +## Scopes ![Admin Architect - Scopes](http://docs.adminarchitect.com/images/index/scopes.jpg) -As like as for filters feature, if Resource implements interface `Filtrable` it will parse the Eloquent model for any available scopes (having no dynamic arguments). - -Use scopes to create sections of mutually exclusive resources for quick navigation and reporting. +AdminArchitect uses scopes to create sections of mutually exclusive resources for quick navigation and reporting. This will add a `tab` bar above the index table to quickly filter your collection on pre-defined scopes. -In addition, if your model implements `SoftDeletes` contract, useful scopes like `withTrashed`, `onlyTrashed` will be available too. - -To hide a scope just add it to Resource `$hiddenScopes` array: +If you want an Eloquent scope to be a part of AdminArchitect scopes, just annotate it using built-in `@ScopeFilter` annotation. ```php -protected $hiddenScopes = ['active']; -``` +/** + * @ScopeFilter() + * @param Builder $query + * @return Builder + */ +public function scopeActive(Builder $query) +{ + return $query->where('active', true); +} -If for some reason you don't want to create new Model's scope you are able to define isolated, Resource-related scopes, like so: +/** + * @ScopeFilter() + * @param Builder $query + * @return Builder + */ +public function scopeInactive(Builder $query) +{ + return $query->where('active', false); +} -```php -public function scopes() +/** + * @ScopeFilter(name="Callable", icon="fa-phone") + * @param Builder $query + * @return Builder|\Illuminate\Database\Query\Builder + */ +public function scopeHavingPhone(Builder $query) { - return $this->scaffoldScopes() - ->push( - (new Scope('active')) - # Like columns and hints, scopes are auto-translatable - # parsed keys are: - # 1. administrator::scopes.. - # 2. administrator::scopes.global. - # but you always can use this method like so: - ->setTitle('Scope title') - ->setQuery(function ($query) { - return $query->whereActive(1); - }) - ); + return $query->join('place_details as pd', 'pd.place_id', '=', 'places.id') + ->whereNotNull('pd.phone'); } ``` -_Hint: Few different ways to add a scope._ - -```php -# Queryable class (should have query() method) -(new Scope('name'))->setQuery(Queryable::class); - -# Class@method syntax -(new Scope('name'))->setQuery("User@active"); +In addition, if your model implements `SoftDeletes` contract, useful scopes like `withTrashed`, `onlyTrashed` will be available too. -# Standard, Closure style -(new Scope('name'))->setQuery(function($query) { return $this->modify(); }); +If for some reason you don't want to create new Model's scope you are able to define isolated, Resource-related scopes, like so: -# Callable instance -(new Scope('name'))->setQuery([SomeClass::class, "queryMethod"]); +```php +public function scopes() +{ + return $this->scaffoldScopes()->push( + (new Scope('name'))->setQuery(function($query) { + $query->where('updated_at', '>=', Carbon::today()->subWeek()); + }); + ); +} ``` diff --git a/docs/Listing/grid.md b/docs/Listing/grid.md index e2f670d..e5120c1 100644 --- a/docs/Listing/grid.md +++ b/docs/Listing/grid.md @@ -1,4 +1,4 @@ -## Index Screen +# Index Screen Admin Architect makes any resource available by default for listing. Any `$fillable`, `$translatedAttributes`, `indexed` and `$dates` columns will be available for listing by default. @@ -7,7 +7,7 @@ In many cases you will probably leave resources untouched, but sometimes complex _[Note]: .dot notation also works while referencing the relationship columns._ -### Grid +## Grid ![Admin Architect - Columns Grid](http://docs.adminarchitect.com/images/index/columns.jpg) @@ -24,42 +24,34 @@ public function columns() $this ->scaffoldColumns() # remove unnecessary columns - ->without(['dates', 'some_other_column']) + ->except(['dates', 'some_other_column']) # add a new table column element - ->push('note') + ->push(Text::make('note')) # add a HasOne or BelongsTo relationship column (Ex.: $eloquent->profile->phone) - ->push('profile.phone') + ->push(HasOne::make('profile')) # if you want to controle the ouput, the callback # function is available as second argument. - ->push('profile.phone', function(Element $element) { + ->push(HasOne::make('profile'), function(Element $element) { # custom output goes here... - return '.....; + return '.....'; return view('path.to.view')->with([...$args]); }) # Assuming that comments is a HasMany or ManyToMany relationship, the # $eloquent->comments->count() will be inserted into a comments column - ->insert('comments', 'after:note') + ->insert(Textarea::make('comments'), 'after:note') # move element to a position - ->move('note', 'after:body') + ->move(Textarea::make('note'), 'after:body') # Add a group of new elements - ->group('meta', function (Group $group) { + ->stack('meta', function (Group $group) { # Note that .dot notation means relationship, like $post->meta->keywords - $group->push('meta.keywords'); - $group->push('meta.description'); - }) - - # or Join existing elements to a group - ->join(['meta.title', 'meta.description', 'meta.keywords'], 'meta') - - # update a group - ->update('meta', function ($group) { - return $group->move('meta.title', 'before:meta.description'); + $group->push(Text::make('keywords')); + $group->push(Textarea::make('description')); }) # update an element @@ -80,11 +72,7 @@ public function columns() # change input type to a dropdown - $element->setInput( - (new Select('someElement'))->setOptions(['dropdown', 'options']) - ) - - return $element; + return Enum::make('someElement')->setOptions(['dropdown', 'options']); }); } ``` @@ -93,12 +81,11 @@ Note: `scaffoldColumns()` method returns a `Mutable` collection extended with so * push($element, \Closure $callback = null) - insert new element to the end of collection * insert($element, $position, \Closure $callback = null) - insert new element to a position (integer, 'before:target', 'after:targer' values accepted) -* without($element) -> remove element[s] +* except($element) -> remove element[s] * move($element, $position) -> move element, position: integer|before:target|after:target * moveBefore($element, $target) * moveAfter($element, $target) * update($element, $callback) - update an element * updateMany(array $elements) - update many elements at once -* group($id, Closure $callback) -> create a new group of elements -* join(array $elements, $id, $position) - join existing elements into a group +* stack(array $elements, $id, $position) - join existing elements into a group * find($element) - find an element From 199571a207aa6dbc2cb31e1ea9378d5333627a30 Mon Sep 17 00:00:00 2001 From: Anatolii Date: Mon, 3 Feb 2020 15:18:27 +0200 Subject: [PATCH 2/2] - replace deprecated method - fix main layout resource class in translation template --- publishes/views/translations/index.blade.php | 2 +- src/Services/Translations/Reader.php | 3 ++- src/Services/TranslationsManager.php | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/publishes/views/translations/index.blade.php b/publishes/views/translations/index.blade.php index 3d71fb3..f796f0a 100644 --- a/publishes/views/translations/index.blade.php +++ b/publishes/views/translations/index.blade.php @@ -1,4 +1,4 @@ -@extends($resource->template()->layout()) +@extends(\Terranet\Administrator\Architect::template()->layout()) @inject('config', 'scaffold.config') diff --git a/src/Services/Translations/Reader.php b/src/Services/Translations/Reader.php index 9b6081b..54a6dda 100644 --- a/src/Services/Translations/Reader.php +++ b/src/Services/Translations/Reader.php @@ -2,6 +2,7 @@ namespace Terranet\Administrator\Services\Translations; +use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Terranet\Localizer\Locale; @@ -22,7 +23,7 @@ public function read(Collection $files, Collection $locales) if (file_exists($path = $this->pathToFile($file, $locale))) { $content[$file] = include_once $path; - foreach (array_dot($content) as $key => $value) { + foreach (Arr::dot($content) as $key => $value) { $translations[$key][$locale->iso6391()] = $value ? $value : ''; } } diff --git a/src/Services/TranslationsManager.php b/src/Services/TranslationsManager.php index 14bcd7a..719a57f 100644 --- a/src/Services/TranslationsManager.php +++ b/src/Services/TranslationsManager.php @@ -4,6 +4,7 @@ use Illuminate\Filesystem\Filesystem; use Illuminate\Support\Collection; +use Illuminate\Support\Str; use Terranet\Administrator\Services\Translations\Reader; use Zend\Code\Generator\ValueGenerator; @@ -122,7 +123,7 @@ protected function files($only = null): Collection ); $files = $files->map(function ($file) { - return str_replace_last('.php', '', basename($file)); + return Str::replaceLast('.php', '', basename($file)); }, $files); }