{"id":18564905,"url":"https://github.com/bdcrops/module-simplenews","last_synced_at":"2025-10-23T18:52:02.903Z","repository":{"id":62492472,"uuid":"206247516","full_name":"bdcrops/module-simplenews","owner":"bdcrops","description":"BDC_SimpleNews full-fledged Module Step by Step","archived":false,"fork":false,"pushed_at":"2020-01-01T07:20:49.000Z","size":3206,"stargazers_count":3,"open_issues_count":0,"forks_count":4,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-04-09T19:22:51.131Z","etag":null,"topics":["certified-associate-developer-exam","certified-professional-developer","console-comand","declarative-programming","declarative-schema","declarative-schema-in-magento2","magento-2-certified","magento-certification","magento2-extension","observer","php-framework","plugins","professional-developer-plus","simplenews","study-notes","weapi"],"latest_commit_sha":null,"homepage":"https://www.bdcrops.com","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bdcrops.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-09-04T06:27:15.000Z","updated_at":"2024-04-09T19:22:51.131Z","dependencies_parsed_at":"2022-11-02T11:16:18.014Z","dependency_job_id":null,"html_url":"https://github.com/bdcrops/module-simplenews","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bdcrops%2Fmodule-simplenews","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bdcrops%2Fmodule-simplenews/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bdcrops%2Fmodule-simplenews/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bdcrops%2Fmodule-simplenews/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bdcrops","download_url":"https://codeload.github.com/bdcrops/module-simplenews/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223424323,"owners_count":17142745,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["certified-associate-developer-exam","certified-professional-developer","console-comand","declarative-programming","declarative-schema","declarative-schema-in-magento2","magento-2-certified","magento-certification","magento2-extension","observer","php-framework","plugins","professional-developer-plus","simplenews","study-notes","weapi"],"created_at":"2024-11-06T22:16:47.538Z","updated_at":"2025-10-23T18:51:57.851Z","avatar_url":"https://github.com/bdcrops.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# Magento 2 SimpleNews module  \n\n**Magento 2 Module development** or **Magento 2 SimpleNews Module**  Create a full-fledged Module Step by Step. You could just follow my code to create this module from the scratch. Or you can directly download the compressed tar file and install it and play it.  \n\n## PREREQUISITES\n- No prerequisites\n- May be More benefited Who are know Magento 2 Basic frontend , backend \u0026 install local/server .\n- Fundamentals of Magento 2 Development or Module Development  as a first step.\n\n\n## Goal:\n\n- Develop Full-fledged Module Step by Step .\n- Magento 2 Certified [Associate](mcad.md)/[Professional](mcpd.md) Developer exam Preparation hands-on practice.\n\n\n\n\n\n## \u003ca name=\"top\"\u003e Magento 2 SimpleNews Module Step By Step (BDCrops) \u003c/a\u003e\n\n###  [PartA: News Module Basic (Architecture \u0026 Customization)](#PartA)\n\n\n- [Step 2A1: Create a directory for the module like above format](#Step2A1)\n- [Step 2A2: Declare module by using configuration file module.xml](#Step2A2)\n- [Step 2A3: Register module by registration.php \u0026 composer.json](#Step2A3)\n- [Step 2A4: Configure declarative schema (create table etc/db_schema.xml)](#Step2A4)\n- [Step 2A5: Schema whitelist (etc/db_schema_whitelist.json) ](#Step2A15)\n- [Step 2A6: Enable the module](#Step2A6)\n- [Step 2A7: Develop data \u0026 schema patches(Installing \u0026 upgrading data)](#Step2A7)\n- [Step 2A8: Create Model News for business Logic](#Step2A8)\n- [Step 2A9: Create Model's ResourceModel to handle real database transaction](#Step2A9)\n- [Step 2A10: Create Model's collection class](#Step2A10)\n- [Step 2A11: Setup the frontend route](#Step2A11)\n- [Step 2A12: Create IndexController](#Step2A12)\n\n\n### [Part B: News Module for Back End](#PartB)\n- [Step 2B1: Setup Module's backend configuration](#Step2B1)\n- [Step 2B2:  Create a custom source model](#Step2B2)\n- [Step 2B3:  Create a role for this config section](#Step2B3)\n- [Step 2B4:  Set some default value for configuration options](#Step2B4)\n- [Step 2B5:  Create a Helper Data class](#Step2B5)\n- [Step 2B6:  Create the menu for Magento backend](#Step2B6)\n- [Step 2B7:  Create backend route file](#Step2B7)\n- [Step 2B8:  Update the acl.xml to add more roles](#Step2B8)\n- [Step 2B9:  Create layout for grid](#Step2B9)\n- [Step 2B10:  Create layout for Grid Container](#Step2B10)\n- [Step 2B11:  Create layout for ajax load](#Step2B11)\n- [Step 2B12:  Create news status option file](#Step2B12)\n- [Step 2B13:  Create News Block for backend](#Step2B13)\n- [Step 2B14:  Create Grid block file for Ajax load](#Step2B14)\n- [Step 2B15: Create backend controller for child action class to extend](#Step2B15)\n- [Step 2B16:  Create Backend Action file Index.php](#Step2B16)\n- [Step 2B17:  Create another Action for ajax](#Step2B17)\n- [Step 2B18:  Create layout file simplenews_news_edit.xml for edit form](#Step2B18)\n- [Step 2B19:  Create the layout for create form](#Step2B19)\n- [Step 2B20:  Create a form container block](#Step2B20)\n- [Step 2B21:  create a block for the left-side tabs](#Step2B21)\n- [Step 2B22:  Create a block for Form information](#Step2B22)\n- [Step 2B23:  Create a block to declare the fields for the edit form](#Step2B23)\n- [Step 2B24:  Create a controller action for create a new News](#Step2B24)\n- [Step 2B25:  Create Edit Action for the Edit form](#Step2B25)\n- [Step 2B26:  A Save Action for the edit form](#Step2B26)\n- [Step 2B27:  Delete Action for the edit Form](#Step2B27)\n- [Step 2B28:  The mass delete action the grid list](#Step2B28)\n- [Step 2B29:  Backend Menu and Grid List](#Step2B29)\n\n### [Part C : News Module for Front End](#PartC)\n- [Step 2C1:  Create Layout file for page handle](#Step2C1)\n- [Step 2C2:  Create another layout file by update the previous layout](#Step2C2)\n- [Step 2C3:  Create Block NewList file](#Step2C3)\n- [Step 2C4:  Create frontend template file list.phtml](#Step2C4)\n- [Step 2C5:  Create an abstract class by extending Magento Core Action class](#Step2C5)\n- [Step 2C6:  Update Index Controller by extends the abstract class 'New.php'](#Step2C6)\n- [Step 2C7:  Create a layout file for news detail page](#Step2C7)\n- [Step 2C8:  Create News view action](#Step2C8)\n- [Step 2C9:  create view news block](#Step2C9)\n- [Step 2C10:  Create news view template file](#Step2C10)\n- [Step 2C11:  Create CSS file for styling the frontend Page](#Step2C11)\n- [Step 2C12:  Create Latest New Block](#Step2C12)\n- [Step 2C13:  Create a Block for positioning the latest news: Left or Right](#Step2C13)\n- [Step 2C14:  Create the template file for Latest News](#Step2C14)\n- [Step 2C15:  Frontend view for the module](#Step2C15)\n\n### [Part D : News Console/Command](#PartD)\n- [Step 2D1:  Adding a new command Dependency Injection](#Step2D1)\n- [Step 2D2:  Adding a new command class](#Step2D3)\n- [Step 2D3:  Adding a new command Helper class](#Step2D3)\n\n### [Part E : Create/Set / Configure Custom Cron Jobs](#PartE)\n- [Step 2E.1:  Create crontab.xml ](#Step2E1)\n- [Step 2E.2:  defined to run the execute method of class](#Step2E3)\n- [Step 2E.3:  Run all cron jobs ](#Step2E3)\n- [Step 2E.4:  Create custom cron group ](#Step2E4)\n- [Step 2E.5:  Run new cron group cron jobs ](#Step2E5)\n\n### [Part F : Create  REST WEB API](#PartF)\n- [Step2F1: Web API Routes/Configuration](#Step2F1)\n- [Step2F2: Define Interface– etc/di.xml](#Step2F2)\n- [Step2F3: Declare API Interface](#Step2F3)\n- [Step2F4: Declare Data API Interface](#Step2F4)\n- [Step2F5: Create Model](#Step2F5)\n- [Step2F6: Communicating with new API call](#Step2F6)\n- [Step2F7: Adding ACL Web API](#Step2F7)\n\n### [PartG: Dependency Injection configuration ](#PartG)\n- [Step2G.1: DI Preference,Arguments \u0026 Virtual Types Implements](#Step2G1)\n- [Step2G.2: DI Observer Implements](#Step2G2)\n- [Step2G.3: DI Plugins (Interceptors)](#Step2G3)\n\n### [PartH : Customization Layout Configuration \u0026 JavaScript ](#PartH)\n- [Step2H.1: Layout Configuration](#Step2H1)\n- [Step2H.2: Customization JavaScript Map \u0026 Mixin](#Step2H2)\n\n### [PartI : UI Components Library](#PartI)\n- [Step2I1: Rendering Grid(collections \u0026 listing component configuration)](#Step2I1)\n- [Step2I.2: Rendering Form ()](#Step2I2)\n\n### [PartJ : Entity-Attribute-Value (EAV)](#PartJ)\n- [Step2J1: Rendering Grid(collections \u0026 listing component configuration)](#Step2J1)\n- [Step2J2: ](#Step2J2)\n\n\n***\n\n##  \u003ca name=\"PartA\"\u003ePart A : News Module for Basic \u003c/a\u003e [Go to Top](#top)\n\n\n#### Explain Magento 2 Basic Directory Structure ?\n\n- app – is used for additional elements; as a rule, app contains the following subdirectories:\n    - code – contains the installed modules;\n    - design – contains the installed themes. The frontend themes are located at the frontend folder; themes for admin panel – in the adminhtml folder;\n    - etc – contains the Magento 2 configuration files;\n    - i18n – contains the installed language packs.\n- bin – contains Magento file responsible for the execution of CLI-commands in Magento 2.\n- dev – contains Integration and Functional test files.\n- generated – utilized for generated classes in Magento 2.\n- lib – contains Magento 2 libraries and non-module based code.\n- phpserver – contains Router.php file, implemented to realize the built-in PHP server.\n- pub – used for static files storage:\n    - errors – contains files responsible for displaying errors in the browser (this behavior is by default disabled);\n    - media – contains all media-files from the website;\n    - static – contains the generated theme and module files.\n- var – contains temporary files, like:\n    - cache – contains all the cached objects, except for pages;\n    - composer_home – root directory of the installation wizard;\n    - log – stores Magento 2 logs;\n    - page_cache – contains pages cached with Full Page Cache;\n    - view_preprocessed – contains minified templates and compiled LESS.\n- vendor – contains core files of Magento 2. Moreover, this directory can contain the additionally installed modules. You should perform operations with components from this directory via Composer.\n\n\n#### What is Model View ViewModel (MVVM) Architecture ?\n\n![](doc/MVVMPattern.png)\n\n- Model: Holds business logic of  application \u0026 depends on an associated class—the ResourceModel—for database access. Models rely on service contracts to expose their functionality to  other layers of  application.\n- View: Structure \u0026 layout of what a user sees on a screen - the actual HTML. This is achieved in the PHTML files distributed with modules. PHTML files are associated to each ViewModel in the Layout XML files, which would be referred to as binders in the MVVM dialect. The layout files might also assign JavaScript files to be used in the final page.\n- ViewModel: Interacts with  Model layer, exposing only  necessary information to  View layer handled by the module’s Block classes. Note that this was usually part of the Controller role of an MVC system. On MVVM, the controller is only responsible for handling the user flow, meaning that it receives requests and either tells the system to render a view or to redirect the user to another route.\n\n#### Magento 2 architecture is split into 4 (PDSP)layers?\n\n![](doc/archi_diagrams_layers_alt4.jpg)\n\n- Persistence layer: describes resource model, which is responsible for extracting and modifying data in the database using CRUD requests.Additional business logic capabilities are also implemented here, for example, data validation and database functions implementation.\n- Domain layer: responsible for the business logic, which does not contain resource-specific or database-specific information. Domain layer can also include service contracts.Each data model at the level of domain layer depends on the resource model, which is responsible for accessing the database.\n- Service layer: interlayer between presentation layer and domain layer. It implements service contracts, which are defined using PHP interfaces. Service contracts allow to add or change business logic resource model using dependency injection file (di.xml). Service layer is also used for granting access to API (REST/SOAP or other modules).Service interface is declared in /Api namespace of the module.\nData (entity) interface is declared in /Api/Data. Data entities are data structures passed to and returned from service interfaces.\n\n- Presentation Layer: upper layer. It contains all the View elements (including layouts, blocks, templates, css, js) and controllers.Presentation Layer usually calls service layer using service contracts. But, depending on the implementation, it may overlap with business logic.\n\n#### Magento has 5 areas types?\n\n- Magento Admin (adminhtml): entry point for this area is index.php or pub/index.php. The Admin panel area includes the code needed for store management. The /app/design/adminhtml directory contains all the code for components you’ll see while working in the Admin panel.\n- Storefront (frontend): entry point for this area is index.php or pub/index.php. The storefront (or frontend) contains template and layout files that define the appearance of your storefront.\n- Basic (base): used as a fallback for files absent in adminhtml and frontend areas.\n- Cron (crontab): In cron.php, the \\Magento\\Framework\\App\\Cron class always loads the 'crontab' area.\nYou can also send requests to Magento using the SOAP and REST APIs. These two areas:\n- Web API REST (webapi_rest): entry point for this area is index.php or pub/index.php. The REST area has a front controller that understands how to do URL lookups for REST-based URLs.\n- Web API SOAP (webapi_soap): entry point for this area is index.php or pub/index.php.\n\n#### Module  folder holds one part of the architecture, as follows?\n\n- Api or Api/Data: Service contracts, defining service interfaces \u0026 data interfaces\n\n- Adapter:Classes follow  adapter pattern \u0026 wrap around classes from third-party libraries allow  to use functionality from third-party libraries in  code by converting the third-party class interfaces into an interface that is expected by  native code.( module-search/Adapter/)\n- Block:  ViewModels of our MVVM architecture\n- Collector: module-deploy/Collector/Collector.php\n- Command: directory is used for storing the PHP files that are responsible for console programs execution. In our case, Console/Command/ImagesResizeCommand.php processes commands for product images resizing.\n- Controller: Responsible for handling the user’s flow while interacting with the system\n- Config: module-deploy/Config/BundleConfig.php\n- Cron: We use the directory to store the files, which are later executed on the Cron launching.\n- CustomerData: directory contains PHP files responsible for processing information for sections. Magento 2 has a special functionality, which allows for processing, updating and transferring the information asynchronously.\n- etc: Configuration XML files  module defines itself \u0026 its parts (routes, models, blocks, observers, and cron jobs) within this folder, also be used by non-core modules to override the functionality of core modules.\n    - [etc/acl.xml](etc/acl.xml)\n    - [etc/adminhtml/menu.xml](etc/adminhtml/menu.xml)\n    - [etc/adminhtml/system.xml](etc/adminhtml/system.xml)\n    - etc/{area}/routes.xml\n    - etc/{area}/events.xml\n    - etc/crontab/events.xml\n    - etc/config.xml\n    - etc/cron_groups.xml\n    - etc/crontab.xml\n    - [etc/db_schema.xml](etc/db_schema.xml)\n    - [etc/di.xml](etc/di.xml)\n    - etc/events.xml\n    - etc/module.xml\n    - etc/setup/events.xml\n    - etc/webapi.xml\n    - etc/webapi_rest/di.xml\n    - etc/webapi_rest/events.xml\n    - etc/webapi_soap/events.xml\n    [ReadDevDoc](https://devdocs.magento.com/guides/v2.3/config-guide/config/config-files.html)\n\n- Exception: (module-sales/Exception/)\n- Files: Sample file  (module-inventory-import-export/Files/)\n- fixtures: Sample Data module (module-sales-sample-data/fixtures/orders.csv)\n- Gateway: (module-paypal/Gateway)\n- Helper: Classes that hold code used in more than one application layer. For example, in the Cms module, helper classes are responsible for preparing HTML for presentation to the browser.\n- i18n: Holds internationalization CSV files, used for translation\n- Indexer: IndexHandler  (module-inventory-indexer/Indexer)\n- Model: For Models and ResourceModels\n- Observer: Holds Observers, or Models which are “observing” system events. Usually, when such an event is fired, the observer instantiates a Model to handle the necessary business logic for such an event.\n- Package: module-deploy/Package\n- Pricing: Final price model  (module-msrp-grouped-product/Pricing)\n- Process: module-deploy/Process\n- Plugin: directory comprises plugin files  allow us to modify certain module’s functions if necessary described in the configuration file: vendor/magento/module-catalog/etc/di.xml\n- SearchAdapter: module-elasticsearch/SearchAdapter\n- ReportXml :vendor/magento/module-analytics/ReportXml\n- Setup: Migration classes, responsible for schema \u0026 data creation\n- Service: [exam] (module-media-storage/Service/ImageResize.php,module-deploy/ or module-catalog-url-rewrite/Service/V1/StoreViewService.php )\n- src : vendor/magento/magento2-functional-testing-framework/src/Magento/\n- Strategy: module-deploy/Strategy\n- Source: module-deploy/Source\n- Test: Unit tests\n- Ui: Elements such as grids \u0026 forms used in  admin application\n- view – Layout (XML) files \u0026 template (PHTML) files for  front-end \u0026 admin application contains template files, CSS and JS files, module media files. These files are located in subfolders depending on the area of use: adminhtml, frontend or base (common files for the administrative and frontal parts of the site). These subdirectories, in turn, including static view files, design templates, email templates, and layout files:\n    - view/{area}/email – contains emails templates.\n    - view/{area}/layout – contains files for layout modifications.\n    - view/{area}/page_layout – contains files for page_layout modifications.\n    - view/{area}/templates – contains files of the module templates (phtml).\n    - view/{area}/ui_component – contains XML-files of the UI module components.\n    - view/{area}/ui_component/templates\n    - view/{area}/web – contains CSS, JS, static and media module files.\n    - view/{area}/web/js – contains js\n    - view/{area}/web/template – contains html\n    - view/{area}/requirejs-config.js\n\n- ViewModel: (module-sales/ViewModel)\n\n\n\n### \u003ca name=\"Step2A1\"\u003eStep 2A1: Create a directory for the module like above format\u003c/a\u003e\n\nIn this module, we will use `BDCrops` for Vendor name and `SimpleNews` for ModuleName. So we need to make this folder: `app/code/BDC/SimpleNews`\n\n\n\n### \u003ca name=\"Step2A2\"\u003eStep 2A2: Declare module by using configuration file module.xml\u003c/a\u003e\n\nMagento 2 looks for configuration information for each module in that module’s etc directory. We need to create folder etc and add module.xml:\n - Create [etc/module.xml](/etc/module.xml) And the content for this file:\n\n   \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n       ```\n       \u003c?xml version=\"1.0\"?\u003e\n       \u003cconfig xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"urn:magento:framework:Module/etc/module.xsd\"\u003e\n           \u003cmodule name=\"BDC_SimpleNews\" setup_version=\"1.0.0\" /\u003e\n       \u003c/config\u003e\n       ```\n   \u003c/details\u003e\n\nIn this file, we register a module with name `BDC_SimpleNews` and the version is `1.0.0`.\n\n#### Notes[u can skip]:\n- Magento 2 need  Two Mandatory File to  run/activate Module etc/module.xml \u0026 registration.php\n\n### \u003ca name=\"Step2A3\"\u003e Step 2A3: Register module by registration.php\u003c/a\u003e\n\nAll Magento 2 module must be registered in the Magento system through the magento ComponentRegistrar class. This file will be placed in module root directory.\nIn this step, we need to create this file:\n- Create  [registration.php](registration.php) and insert this following code into it:\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n    ```\n    \\Magento\\Framework\\Component\\ComponentRegistrar::register(\n        \\Magento\\Framework\\Component\\ComponentRegistrar::MODULE,\n        'BDC_SimpleNews', __DIR__\n    );\n    ```\n  \u003c/details\u003e\n\nModules in vendor folder would update using composer And all the modules in app/code would not be updated through composer That's why when you need to override any module you add it in app/code\n\n- Create  [composer.json](composer.json)  and insert this following code into it:\n\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n      ```\n      {\n        \"name\": \"bdc/module-simplenews\",\n        \"description\": \"BDCrops SimpleNews module for Magento 2 extensions.\",\n        \"type\": \"magento2-module\",\n        \"version\": \"1.0.3\",\n        \"license\": [\n            \"OSL-3.0\",\n            \"AFL-3.0\"\n        ],\n      \"authors\": [{\n                \"name\": \"Abdul Matin\",\n                \"email\": \"matinict@gmail.com\",\n      \t\t      \"company\": \"BDCrops Inc\"\n            }\n        ],\n      \"homepage\": \"https://www.bdcrops.com\",\n        \"autoload\": {\n            \"files\": [\n                \"registration.php\"\n            ],\n            \"psr-4\": {\n                \"BDC\\\\SimpleNews\\\\\": \"\"\n            }\n        }\n      }\n\n      ```\n  \u003c/details\u003e\n\n### \u003ca name=\"Step2A4\"\u003eStep 2A4: Configure declarative schema (create table  schema Installation file)\u003c/a\u003e\n\n- Create [etc/db_schema.xml](etc/db_schema.xml) \u0026  insert this following code into it:\n\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n      ```\n      \u003c?xml version=\"1.0\"?\u003e\n      \u003cschema xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd\"\u003e\n\n      \u003ctable name=\"bdc_simplenews\" resource=\"default\" engine=\"innodb\" comment=\"SimpleNews Table\"\u003e\n        \u003ccolumn xsi:type=\"smallint\" name=\"id\" padding=\"6\" unsigned=\"false\" nullable=\"false\" identity=\"true\" comment=\"ID\"/\u003e\n        \u003ccolumn xsi:type=\"varchar\" name=\"title\" nullable=\"false\" length=\"255\" comment=\"Title\"/\u003e\n        \u003ccolumn xsi:type=\"varchar\" name=\"summary\" nullable=\"false\" length=\"255\" comment=\"Summary\"/\u003e\n        \u003ccolumn xsi:type=\"varchar\" name=\"description\" nullable=\"false\" length=\"255\" comment=\"Descrition\"/\u003e\n        \u003ccolumn xsi:type=\"timestamp\" name=\"created_at\" nullable=\"false\" default=\"CURRENT_TIMESTAMP\" on_update=\"false\" comment=\"Created Datetime\"/\u003e\n        \u003ccolumn xsi:type=\"timestamp\" name=\"updated_at\" nullable=\"false\" default=\"CURRENT_TIMESTAMP\" on_update=\"true\" comment=\"Updated Datetime\"/\u003e\n        \u003ccolumn xsi:type=\"smallint\" name=\"status\"  padding=\"2\" unsigned=\"false\" nullable=\"false\" comment=\"Status\"/\u003e\n        \u003cconstraint xsi:type=\"primary\" referenceId=\"PRIMARY\"\u003e   \u003ccolumn name=\"id\"/\u003e \u003c/constraint\u003e\n      \u003c/table\u003e\n      \u003c/schema\u003e\n      ```\n  \u003c/details\u003e\n\n\n#### Note:\n[Tutarials module-declarative](https://github.com/bdcrops/module-declarative)\n\n### \u003ca name=\"Step2A5\"\u003eStep 2A5: Schema whitelist (etc/db_schema_whitelist.json) \u003c/a\u003e\n\nYou will not be able to run a declarative mode without creating a schema whitelist.\nNote: it is recommended to generate a new whitelist for every release for the double-check purposes.Before running the upgrade command you need to add your schema to db_whitelist_schema.json file by running the following command.\nFor that, you need a /etc/db_schema_whitelist.json file that will store all the content added with declarative schema. To generate this file, run:\n\n\n![db_schema](https://github.com/bdcrops/BDC_Declarative/blob/master/view/adminhtml/web/images/whitelist.png)\n\n```\nphp bin/magento setup:db-declaration:generate-whitelist [options]\nphp bin/magento setup:db-declaration:generate-whitelist --module-name=vendor_module\nphp bin/magento setup:db-declaration:generate-whitelist --module-name=BDC_SimpleNews\n```\n\nNow, there are db_whitelist_schema.json file will be create in /vendor/module/etc folder.\n![db_whitelist_schema](https://github.com/bdcrops/BDC_SimpleNews/blob/master/doc/db_schema_whitelist.png)\n\n\n\n### \u003ca name=\"Step2A6\"\u003eStep 2A6: Enable the module\u003c/a\u003e\n\n\nBy finish above step, you have created an empty module. Now we will enable it in Magento environment.Before enable the module, we must check to make sure Magento has recognize our module or not by enter the following at the command line:\n\n~~~\nphp bin/magento module:status\n~~~\n\nIf you follow above step, you will see this in the result:\n\n~~~\nList of disabled modules:\nBDC_SimpleNews\n~~~\n\nThis means the module has recognized by the system but it is still disabled. Run this command to enable it:\n\n~~~\nphp bin/magento module:enable BDC_SimpleNews\n~~~\n\nThe module has enabled successfully if you saw this result:\n\n~~~\nThe following modules has been enabled:\n- BDC_SimpleNews\n~~~\n\nThis’s the first time you enable this module so Magento require to check and upgrade module database. We need to run this comment:\n\n~~~\nphp bin/magento setup:upgrade\n~~~\n\nNow you can check under `Stores -\u003e Configuration -\u003e Advanced -\u003e Advanced` that the module is present.\n\nAlso  you can check Database Table from PhpMyAdmin or Your Favorite tools:\n\n![Table db_schema](https://github.com/bdcrops/BDC_SimpleNews/blob/master/doc/dbTableCreatedDeclarativeSchema.png)\n\n\n\n### \u003ca name=\"Step2A7\"\u003eStep 2A7:  Develop data and schema patches (Insert data Installing and upgrading data)\u003c/a\u003e\n\n\nSince in the old method, we used to write scripts in Install Schema or Upgrade schema when a table was created, but now in the new version, this will be done through Patch system.A data patch is a class that contains data modification instructions. It is defined in a \u003cNamespace\u003e/\u003cModule_Name\u003e /Setup/Patch/Data/\u003cPatch_Name\u003e.php file and implements \\Magento\\Setup\\Model\\Patch\\DataPatchInterface.\nA schema patch contains custom schema modification instructions. These modifications can be complex.\nIt is defined in a\u003cVendor\u003e/\u003cModule_Name\u003e/Setup/Patch/Schema/\u003cPatch_Name\u003e.php file and implements \\Magento\\Setup\\Model\\Patch\\SchemaPatchInterface.\nSo to add data to the bdc_simplenews table create AddData.php file inside folder BDC/SimpleNews/Setup/Patch/Data and write the following code\n\n- Create [Setup/Patch/Data/AddData.php](Setup/Patch/Data/AddData.php)\n\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n      ```\n      \u003c?php\n\n      namespace BDC\\SimpleNews\\Setup\\Patch\\Data;\n\n      use Magento\\Framework\\Setup\\Patch\\DataPatchInterface;\n      use Magento\\Framework\\Setup\\Patch\\PatchVersionInterface;\n      use Magento\\Framework\\Module\\Setup\\Migration;\n      use Magento\\Framework\\Setup\\ModuleDataSetupInterface;\n\n      class AddData implements DataPatchInterface, PatchVersionInterface {\n          private $news;\n          public function __construct( \\BDC\\SimpleNews\\Model\\News $news ) {\n              $this-\u003enews = $news;\n          }\n          public function apply(){\n          \t$newsData = [];\n          \t$newsData['title'] = \"BDC News Head1\";\n          \t$newsData['summary'] = \"BDC News Summary\";\n          \t$newsData['description'] = \"BDCrops Inc description evulation of bangladesh\";\n          \t//$newsData['status'] = 1;\n\n          \t$this-\u003enews-\u003eaddData($newsData);\n          \t$this-\u003enews-\u003egetResource()-\u003esave($this-\u003enews);\n\n          }\n          public static function getDependencies() {   return []; }\n          public static function getVersion() { return '2.0.0'; }\n          public function getAliases() {   return []; }\n\n      }\n\n      ```\n  \u003cdetails\u003e\n\n### \u003ca name=\"Step2A8\"\u003e Step 2A8: Create Model News for business Logic\u003c/a\u003e\n\nWe need to create these files to insert, update, delete and get data in the database.\n\n- Create model file: [Model/News.php](Model/News.php):\n\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n      ```\n      \u003c?php\n      // These files to insert, update, delete and get data in the database.\n      namespace BDC\\SimpleNews\\Model;\n      use Magento\\Framework\\Model\\AbstractModel;\n\n      class News extends AbstractModel{\n          /**\n           * News constructor.\n           * @param \\Magento\\Framework\\Model\\Context $context\n           * @param \\Magento\\Framework\\Registry $registry\n           * @param \\Magento\\Framework\\Model\\ResourceModel\\AbstractResource|null $resource\n           * @param \\Magento\\Framework\\Data\\Collection\\AbstractDb|null $resourceCollection\n           * @param array $data\n           */\n          public function __construct(\n              \\Magento\\Framework\\Model\\Context $context,\n              \\Magento\\Framework\\Registry $registry,\n              \\Magento\\Framework\\Model\\ResourceModel\\AbstractResource $resource = null,\n              \\Magento\\Framework\\Data\\Collection\\AbstractDb $resourceCollection = null,\n              array $data = [] ) {\n              parent::__construct($context, $registry, $resource, $resourceCollection, $data);\n          }\n\n         /**\n          * (non-PHPdoc)\n          * @see \\Magento\\Framework\\Model\\AbstractModel::_construct()\n          */\n          public function _construct(){\n              $this-\u003e_init('BDC\\SimpleNews\\Model\\Resource\\News');\n          }\n\n          /**\n           * Loading news data\n           *\n           * @param   mixed $key\n           * @param   string $field\n           * @return  $this\n           */\n          public function load($key, $field = null) {\n            if ($field === null) {\n              $this-\u003e_getResource()-\u003eload($this, $key, 'id');\n              return $this;\n            }\n            $this-\u003e_getResource()-\u003eload($this, $key, $field);\n            return $this;\n          }\n      }\n\n      ```\n\n  \u003cdetails\u003e\n\n\n#### \u003ca name=\"Step2A8Note1\"\u003e Note: basic concepts of models, resource models, and collections\u003c/a\u003e\nCRUD Models in Magento 2 can manage data in database easily, you don’t need to write many line of code to create a CRUD. CRUD is stand for Create, Read, Update and Delete.\nThe Magento ORM is used by the Repository implementations that are part of the Magento 2 service contracts. This is an important variation from Magento 1, as a module should no longer rely on other modules using a specific ORM, and instead of it use only the entity repositories. The service contracts will be covered in more details in the second part of the article.The Magento ORM is built around models, resource models, and resource collections. The Magento ORM elements are following:\n\n-  Models are data and behavior, representing entities.\n- Resource Models are data mappers for the storage structure.\n- Collections are encapsulating sets of models and related functionality, such as filtering, sorting, and paging.\n- Resources include database connections via adapters.\n#### \u003ca name=\"Step2A8Note2\"\u003eNote:native Magento save/load \u003c/a\u003e\nThe ORM gives you a possibility to create, load, update, and delete data in a database. A collection in Magento is a class that implements both the IteratorAggregate and the Countable PHP5 SPL interfaces. Collections are widely used in Magento to store a set of objects of a specific type.\n\n#### \u003ca name=\"Step2A8Note3\"\u003eNote: Models\u003c/a\u003e\nModels are like a black box which provides a layer of abstraction on top of the resource models. The fetching, extraction, and manipulation of data occur through models. As a rule of thumb, every entity we create (i.e. every table we create in our database) should have its own model class. Every model extends the Magento\\Framework\\Model\\AbstractModelclass, which inherits the \\Magento\\Framework\\DataObjectclass, hence, we can call the setDataand getData functions on our model, to get or set the data of a model respectively. class only has one method, _ construct(), when we call the _ init()method, and pass the resource model’s name as its paramete\n\n\n### \u003ca name=\"Step2A9\"\u003eStep 2A9: Create Model's ResourceModel to handle real database transaction\u003c/a\u003e\n\n- Create resource model [Model/Resource/News.php](Model/Resource/News.php):\n\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n      ```\n      \u003c?php\n\n      namespace BDC\\SimpleNews\\Model\\Resource;\n\n      use Magento\\Framework\\Model\\ResourceModel\\Db\\AbstractDb;\n\n      class News extends AbstractDb {\n          /**\n           * Define main table\n           */\n          protected function _construct() { $this-\u003e_init('bdc_simplenews', 'id'); }\n      }\n\n      ```\n  \u003c/details\u003e\n\n\n\n#### \u003ca name=\"Step2A9Note1\"\u003eNote: Resource Model\u003c/a\u003e\nAll of the actual database operations are executed by the resource model. Every model must have a resource model, since all of the methods of a resource model expects a model as its first parameter. All resource models must extend the Magento\\Framework\\Model\\ResourceModel\\Db\\AbstractDbclass.\nhere also has one method, \u003c__ construct\u003e, where we call the \u003c_ initmethod\u003e, and pass two parameters to it. The name of the table in the database, and the name of the primary column in that table.\nResource Model. In Magento 2, the model class defines the methods an end-user-programmer will use to interact with a model’s data. A resource model class contains the methods that will actually fetch the information from the database. Each CRUD model in Magento 2 has a corresponding resource model class.\n\nEvery CRUD resource model class extends the Magento\\Framework\\Model\\ResourceModel\\Db\\AbstractDb class. This base class contains the basic logic for fetching information from a single database table.\nFor a basic model like ours, the only thing a resource model must do is call the _ init method from _ construct. The _ init method for a resource model accepts two arguments. The first is the name of the database table (bdc_simplenews), and the second is the ID column for the model (id). While it’s beyond the scope of this article, Magento 2’s active record implementation contains no method for linking tables via primary keys. How to use multiple database tables is up to each individual module developer, and a resource model will typically contain the SQL generating methods needed to fetch information from related tables.\n\n\n### \u003ca name=\"Step2A10\"\u003eStep 2A10: Create Model's collection class\u003c/a\u003e\n\n- Create collection [Model/Resource/News/Collection.php](Model/Resource/News/Collection.php ):\n\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n      ```\n      \u003c?php\n      namespace BDC\\SimpleNews\\Model\\Resource\\News;\n\n      use Magento\\Framework\\Model\\ResourceModel\\Db\\Collection\\AbstractCollection;\n      class Collection extends AbstractCollection {\n          /**\n           * Define model \u0026 resource model\n           */\n          protected function _construct(){\n              $this-\u003e_init('BDC\\SimpleNews\\Model\\News', 'BDC\\SimpleNews\\Model\\Resource\\News');\n          }\n      }\n\n      ```\n\n  \u003c/details\u003e\n\n\n#### \u003ca name=\"Step2A10Note1\"\u003eNote:  Collection \u003c/a\u003e\nCollections are used when we want to fetch multiple rows from our table. Meaning collections\n- group of models. Collections can be used when we want to\n- Fetch multiple rows from a table\n- Join tables with our primary table\n- Select specific columns\n- Apply a WHERE clause to our query\n- Use GROUP BY or ORDER BY in our query\n\nWith a model and resource model, you have everything you need to fetch and save individual models into the database. However, there are times where you’ll want to fetch multiple models of a particular type. To solve this problem, every CRUD model in Magento 2 has a corresponding resource model collection. A collection collects individual models. It’s considered a resource model since it builds the SQL code necessary to pull information from a database table.\nAll collections in Magento 2 extend the base \\Magento\\Framework\\Model\\ResourceModel\\Db\\Collection\\AbstractCollection collection class. Like a model and resource model, a collection resource model must call the _ init method. A collection resource model’s _ init method accepts two arguments. The first is the model that this collection collects. The second is that collected model’s resource model.\nWe create a new Magento 2 block an inject \\Magento\\Catalog\\Model\\ResourceModel\\Product\\CollectionFactory class. This is needed to get a collection from factory. A getProductCollection returns a new product collection. This method does the following:\n\n- create a new collection from collection factory\n- filter attributes (collumns)\n- This time we want to load all data (* ), you can also add a comma seperated list of attribute names. Only this attributes get loaded – lazy loading optimizes your database select statement.\n- filter by attribute values\nIt is possible to filter your collection by loaded attribute values. For example all products with price small than 1000 $. My example use setPageSize() to only load a given number of products.\n\n### \u003ca name=\"Step2A11\"\u003eStep 2A11: Request Flow Processing- Frontend Route\u003c/a\u003e\n\n#### Create custom route on Frontend route?\n\nWe will find how to create a frontend route, admin route and how to use route to rewrite controller.\n- Routes.xml\nTo register a frontend route, we must create a routes.xml file:\nFile: app/code/BDC/SampleNews/etc/frontend/routes.xml\n```\n\u003c!--Use router 'standard' for frontend route--\u003e\n    \u003crouter id=\"standard\"\u003e\n        \u003c!--Define a custom route with id and frontName--\u003e\n        \u003croute frontName=\"samplenews\" id=\"samplenews\"\u003e\n            \u003c!--The module which this route match to--\u003e\n            \u003cmodule name=\"BDC_SampleNews\"/\u003e\n        \u003c/route\u003e\n    \u003c/router\u003e\n```\nPlease look into the code, you will see it’s very simple to register a route. You must use the standard router for the frontend. This route will have a child which define the module for it and 2 attributes:\n\nThe id attribute is a unique string which will identify this route. You will use this string to declare the layout handle for the action of this module\nThe frontName attribute is also a unique string which will be shown on the url request. For example, if you declare a route like this:\n \u003croute frontName=\"samplenews\" id=\"samplenews\"\u003e\nThe url to this module should be:\n\nhttp://example.com/index.php/samplenews/controller/action\nAnd the layout handle for this action is: samplenews_controller_action.xml So with this example path, you must create the action class in this folder:\n~~~\n{namespace}/{module}/Controller/{Controller}/{Action}.php\n\nhttp://example.com/\u003crouter_name\u003e/\u003ccontroller_name\u003e/\u003caction_name\u003e\n~~~\n\nThe Router is used to assign a URL to a corresponding controller and action. In this module, we need to create a route for frontend area. So we need to add this file:\n\n- Create  [etc/frontend/routes.xml](etc/frontend/routes.xml):\n\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n      ~~~\n      \u003c?xml version=\"1.0\"?\u003e\n      \u003cconfig xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n      xsi:noNamespaceSchemaLocation=\"../../../../../../lib/internal/Magento/Framework/\n      App/etc/routes.xsd\"\u003e\n          \u003crouter id=\"standard\"\u003e\n              \u003croute id=\"news\" frontName=\"news\"\u003e\n                  \u003cmodule name=\"BDC_SimpleNews\" /\u003e\n              \u003c/route\u003e\n          \u003c/router\u003e\n      \u003c/config\u003e\n      ~~~\n\n  \u003c/details\u003e\n\n\nAfter define the route, the URL path to our module will be: `http://example.com/news/`\n\n#### \u003ca name=\"Step2A11Note1\"\u003eNote: Controllers, Routers and Responses\u003c/a\u003e\n- Routers: define name for a module which we can use in the url to find the module and execute the controller action.\n- Controllers:Controllers in Magento 2 differ from typical controllers in MVC applications. Magento 2 controllers are responsible for only one specific URL and contain only one execute method. This method is responsible for returning result object and occasional processing of input POST data. All controllers inherit \\Magento\\Framework\\App\\Action\\Action class. The required controller is searched in the Base Router, and then it’s called in the Front Controller.\n- Responses: The controller in Magento 2 can return several response types depending on the purpose and the necessary result.\n\n- Frontend route: Please look into the code, you will see it’s very simple to register a route. You must use the standard router for the frontend. This route will have a child which define the module for it and 2 attributes:\n1. The id attribute is a unique string which will identify this route. You will use this string to declare the layout handle for the action of this module\n2. The frontName attribute is also a unique string which will be shown on the url request. For example, if you declare a route like this: \u003croute frontName=\"news\" id=\"news\"\u003e The url to this module should be:\nhttp://example.com/index.php/nwes/controller/action\nAnd the layout handle for this action is: samplenews_controller_action.xml So with this example path, you must create the action class in this folder: {namespace}/{module}/Controller/{Controller}/{Action}.php\n\n\n\n### \u003ca name=\"Step2A12\"\u003eStep 2A12: Create IndexController\u003c/a\u003e\n\n- Factory Object\nWe are done with creating the database table, CRUD model, resource model and collection. So how to use them?\n\nIn this part, we will talk about Factory Object for model. As you know in OOP, a factory method will be used to instantiate an object. In Magento, the Factory Object do the same thing.\n\nThe Factory class name is the name of Model class and append with the ‘Factory’ word. So for our example, we will have NewsFactory class. You must not create this class. Magento will create it for you. Whenever Magento’s object manager encounters a class name that ends in the word ‘Factory’, it will automatically generate the Factory class in the var/generation folder if the class does not already exist. You will see the factory class:\n\n```\nuse BDC\\SimpleNews\\Model\\NewsFactory;\nvar/generation/\u003cvendor_name\u003e/\u003cmodule_name\u003e/Model/ClassFactory.php\nvar/generation/BDC/SimpleNew/Model/NewsFactory.php\n```\nTo instantiate a model object we will use automatic constructor dependency injection to inject a factory object, then use factory object to instantiate the model object.\n\n#### Magento 2 Registry \u0026 Register?\nMagento 2 authorizes you to register global variable that supports the static registry method. Magento 1, as well as Magento 2, authorize you to register global variable that supports the static registry method.\nTo implement that, maybe you used to work with Mage::register() and Mage::registry() in Magento 1, but now in Magento 2 platform, there is a difference in running the registry. You will be required to apply \\Magento\\Framework\\Registry, that accepts the settings and the registry of the restored data. However, first of all, you need to learn how to create or use the own custom registry and also show you how to retrieve global Magento 2 registry objects like current product, category, cms page, cms block, etc.\nAnd that is lucky because all of them will be referred here. The topic today will help you be familiar with Magento 2 registry objects.\n\n#### How to get and set custom attribute in registry / register\n\n```\n/**\n  * @var \\Magento\\Framework\\Registry\n  */\n\n protected $_registry;\n /**\n * ...\n * ...\n * @param \\Magento\\Framework\\Registry $registry,\n */\npublic function __construct(\n    ...,\n    ...,\n    \\Magento\\Framework\\Registry $registry,\n    ...) {\n    $this-\u003e_registry = $registry;\n    ...\n    ...\n}\n\n /**\n * Setting custom variable in registry to be used\n *\n */\npublic function setCustomVariable() {\n     $this-\u003eregistry-\u003eregister('custom_var', 'Added Value');\n}\n\n/**\n * Retrieving custom variable from registry\n * @return string\n */\npublic function getCustomVariable() {\n     return $this-\u003eregistry-\u003eregistry('custom_var');\n}\n```\n\n\n- Create controller [Controller/Index/Index.php](Controller/Index/Index.php):\n\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n    ```\n      \u003c?php\n\n      namespace BDC\\SimpleNews\\Controller\\Index;\n\n      use Magento\\Framework\\App\\Action\\Action;\n      use Magento\\Framework\\App\\Action\\Context;\n      use BDC\\SimpleNews\\Model\\NewsFactory;\n\n      class Index extends Action {\n          /**\n           * @var \\BDC\\SimpleNews\\Model\\NewsFactory\n           */\n          protected $_modelNewsFactory;\n          /**\n           * @param Context $context\n           * @param NewsFactory $modelNewsFactory\n           */\n          public function __construct(\n              Context $context,\n              NewsFactory $modelNewsFactory ) {\n              parent::__construct($context);\n              $this-\u003e_modelNewsFactory = $modelNewsFactory;\n          }\n          public function execute(){\n              /**\n               * When Magento get your model, it will generate a Factory class\n               * for your model at var/generaton folder and we can get your\n               * model by this way\n               */\n              $newsModel = $this-\u003e_modelNewsFactory-\u003ecreate();\n\n              // Load the item with ID is 1\n              $item = $newsModel-\u003eload(1);\n              var_dump($item-\u003egetData());\n\n              // Get news collection\n              $newsCollection = $newsModel-\u003egetCollection();\n              // Load all data of collection\n              var_dump($newsCollection-\u003egetData());\n          }\n      }\n\n      ```\n  \u003c/details\u003e\n\nAfter define the Controller, the URL path to our module will be: `http://example.com/news/` below data\n\n![NewsDataFrontend](https://github.com/bdcrops/BDC_SimpleNews/blob/master/doc/newsFrontendData.png)\n\n\n#### Notes:\n- Action class: extensions of the Action class that a router returns on matched requests. The execute() function in these classes contain the logic for dispatching requests.Each Action should implement one or more Magento\\Framework\\App\\Action\\HttpHTTP MethodActionInterface to declare which HTTP request methods it can process.Magento has a form key validation in place for all POST non-AJAX requests - if your Action doesn’t need that validation or you want to modify it you can implement CsrfAwareActionInterface.\nIf you need to forward a request to another action in your class, use the _ forward() function. Example:\n```\n$this-\u003e_forward('action', 'controller', 'Other_Module')\n```\n\n#### \u003ca name=\"Step2A12Note1\"\u003e Responses: create a frontend controller with different response types\u003c/a\u003e\n- Page Result (\\Magento\\Framework\\View\\Result\\Page) is the most common type of response. By returning this object, the controller starts the standard page rendering based on the corresponding XML layout handle.\n```\npublic function __construct(\n   $pageFactory Magento\\Framework\\View\\Result\\PageFactory\n) {\n   $this-\u003epageResultFactory = $pageFactory\n}\npublic function execute()\n{\n   return $this-\u003epageResultFactory-\u003ecreate();\n}\n```\n- Raw Result (\\Magento\\Framework\\Controller\\Result\\Raw) is used if you want to return a string to the browser without using Magento layout and view rendering.\n```\npublic function __construct(\n   Magento\\Framework\\Controller\\Result\\Raw $rawResultFactory ,\n) {\n   $this-\u003erawResultFactory = $rawResultFactory;\n}\npublic function execute()\n{\n   $result = $this-\u003erawResultFactory-\u003ecreate();\n   $result-\u003esetHeader('Content-Type', 'text/xml');\n   $result-\u003esetContents('\u003croot\u003e\u003cblock\u003e\u003c/block\u003e\u003c/root\u003e);\n   return $result;\n}\n```\n\n- Forward Result (\\Magento\\Framework\\Controller\\Result\\Forward) allows to call another method/controller without changing the URL or redirecting.\n```\npublic function __construct(\n   Magento\\Framework\\Controller\\Result\\Forward\\Factory $resultForwardFactory    \n) {\n   $this-\u003eresultForwardFactory = $resultForwardFactory;\n}\npublic function execute()\n{\n   $result = $this-\u003eresultForwardFactory-\u003ecreate();\n   $result-\u003eforward('noroute');    \n   return $result;\n}\n```\n- Redirect Result (\\Magento\\Framework\\Controller\\Result\\Redirect) is used when a user needs to be redirected to a different URL.\n```\npublic function __construct(\n   Magento\\Framework\\Controller\\Result\\Redirect\\Factory $resultRedirectFactory\n) {\n   $this-\u003eresultRedirectFactory = $resultRedirectFactory;\n}\npublic function execute()\n{\n   $result = $this-\u003eresultRedirectFactory-\u003ecreate();\n   $result-\u003esetPath('*/*/index');\n   return $result;\n}\n```\n\n***\n\n### \u003ca name=\"PartB\"\u003ePart B: News Module for Back End \u003c/a\u003e   [Go to Top](#top)\n\n\n### What is Scope?\n\nIf your Magento installation has a hierarchy of websites, stores, or views, you can set the context, or “scope” of a configuration setting to apply to a specific part of the installation. The context of many database entities can also be assigned a specific scope to determine how it is used in the store hierarchy. To learn more, see: Product Scope and Price Scope.\n\nSome configuration settings such as postal code, have a [global] scope because the same value is used throughout the system. The [website] scope applies to any stores below that level in the hierarchy, including all stores and their views. Any item with the scope of [store view] can be set differently for each store view, which is typically used to support multiple languages.\n\nUnless the store is running in Single Store Mode, the scope of each configuration setting appears in small text below the field label. If your installation includes multiple websites, stores or views, you should always choose the Store View where the settings apply before making any changes.\n\n![](https://docs.magento.com/m2/ce/user_guide/images/images/scope-multisite.png)\n\n### What is Scope Settings?\n\n- Global:\tSystem-wide settings and resources that are available throughout the Magento installation.\n- Website:\tSettings and resources that are limited to the current website. Each website has a default store.\n- Store:\tSettings and resources that are limited to the current store. Each store has a default root category (main menu) and default store view.\n- Store View:\tSetting and resources that are limited to the current store view.\n\n#### How to write \u0026 get config values by scope?\nAn important, but less good documented feature of Magento 2 is how to write and get config values by scope. You will find tons of code samples on how do this globally. Sometime you need to do different settings for different stores programmatically. So here is how this works.\n\nMagento saves all adminhtml settings in core_config table in your Magento database. There you can get values by its path, a string which indicates path to and a variable name. With this path, you can get or set values by Magento 2 core methods. For this you need to use:\n\n- \\Magento\\Framework\\App\\Config\\Storage\\WriteInterface\nto write config values to database\n- \\Magento\\Framework\\App\\Config\\ScopeConfigInterface\nto read config values from database\n\n#### How  Write store config values by scope?\n\nThe following sample code shows how to write store config values by scope:\n```\nclass WriteConfig {\n    protected $_logger;\n    protected $_storeManager;\n    protected $_configWriter;\n\n    public function __construct(\n        \\Psr\\Log\\LoggerInterface $logger,\n        \\Magento\\Framework\\App\\Config\\Storage\\WriterInterface $configWriter,\n        \\Magento\\Store\\Model\\StoreManagerInterface $storeManager ){\n        $this-\u003e_logger = $logger;\n        $this-\u003e_configWriter = $configWriter;\n        $this-\u003e_storeManager = $storeManager;\n    }\n\n    public function setConfig($value) {\n        //for all websites\n        $websites = $this-\u003e_storeManager-\u003egetWebsites();\n        $scope = \"websites\";\n        foreach($websites as $website) {\n            echo $website-\u003egetId().\":\\n\";\n\n            $this-\u003e_configWriter-\u003esave('my_section/something/configvaluename', $value, $scope, $website-\u003egetId());\n        }\n\n        return $this;\n    }\n}\n```\nYou just need to call setConfig() method with a given value. This method stores this value into a defined path for all websites. So it generates a new setting (line in core_config table) for each defined website. This is done by using third and fourth param on save method. You use a unique path, a value, a scope and the id of this scope. If you do not use scope, you will wirte the value to default (store id 0). You can store values to scopes “website” or “store“.\n\n#### How Read store config values by scope?\n\nNow it is time to read the data by store. You can do this with the following sample code:\n```\nclass ReadConfig\n{\n    protected $_scopeConfig;\n\n    public function __construct(\n        \\Magento\\Framework\\App\\Helper\\Context $context,\n        \\Magento\\Framework\\App\\Config\\ScopeConfigInterface $scopeConfig\n    ){\n        $this-\u003e_scopeConfig = $scopeConfig;\n        parent::__construct($context);\n    }\n\n    public function getConfig() {\n        return $this-\u003e_scopeConfig-\u003egetValue(\"my_section/something/configvaluename\", \"websites\");\n    }\n}\n```\n\nIt is quite easy, you only need to use getValue() method and add a second param with scope (here we use website scope). This will return the stored value for the current website.\n\n#### How to Use Configuration Files in Magento 2?\nThere are 2 main places for storing configuration values In Magento 2: database (the core_config_data table) and XML files. The configurations, stored in the database can be changed via the administrator panel, while the data, located in the XML files are of a technical nature and can be changed only by a developer.\n\nIt’s easy to use configuration files in Magento 2. Configuration files include:\n- app/etc/config.php — contains the declaration of all modules;\n- app/etc/env.php — describes the array, which contains the front end name for the back end panel, the data for connection to the database, the table prefixes, the current store mode, the types and statuses of the cache.\nThese files are generated during the Magento 2 setup. You can change them directly editing the file. However, running terminal commands bin/magento is considered to be best practice.\n\n#### Explain Utilize Configuration XML and Variables Scope in Magento 2?\n\n- etc/config.xml — contains default option values from Stores \u003e Configuration in the admin panel menu. This menu can be configured at system.xml;\n- di.xml — contains configurations for the dependency injection;\n- etc/events.xml — a list of observers and events;\n- etc/routes.xml — a list of routers;\n- etc/config.xml — contains the default values for the module settings Stores \u003e Configuration;\n- etc/acl.xml — adds module resources to a resource tree that allows you to configure access for different users.\n- etc/crontab.xml — adds and configures the task for the cronjob;\n- etc/module.xml — announces the name and the version of the module, as well as its dependencies on other modules;\n- etc/widget.xml — stores the widget settings;\n- etc/indexer.xml — announces a new kind of indexing. It specifies the view_id parameter, which points at the views described in - etc/mview.xml;\netc/mview.xml —  describes the representations of all the indices described in etc/indexer.xml;\n- etc/webapi.xml — defines web API components, which service method to use and which resource to connect for a specific request;\n- etc/view.xml — contains the properties of product images;\n- etc/product_types.xml — describes types of products in a store;\n- etc/product_options.xml — describes the types of options, that can have products and classes to render them;\n- etc/extension_attributes.xml — a new ability to add a custom attribute appeared in Magento 2. This file describes the attribute, its type, which can be simple or complex and represent an interface;\n- etc/catalog_attributes.xml — groups attributes;\n- etc/adminhtml/system.xml — can only apply to the admin area, adds tabs to Stores \u003e Configuration, describes sections and fields of a form;\n- etc/adminhtml/menu.xml — can only apply to the admin area, adds an item to the admin panel menu.\n\n#### Explain loading of configurations occurs in three stages?\n\n- Loading system-level configurations. Loading the files necessary to run Magento 2, such as config.php;\n- Loading global area configurations. Loading the files located in the app/etc/Magento 2 directory, such as di.xml, as well as the files related to the global scope and located directly in the etc/module folders.\n- Loading configurations for specific areas. Loading the files located in the folders etc/adminhtml or etc/frontend.\nConfiguration files are connected according to their complete xPaths. Specific attributes are defined in the $idAttributes array as identifiers. After 2 files are connected, they contain all the nodes and values from the original files. The second XML file either adds or replaces the nodes of the first XML file.\n\n#### What interfaces provides Magento/Framework/Config for developers?\n\nMagento/Framework/Config provides the following interfaces for developers:\n\n- \\Magento\\Framework\\Config\\DataInterface — returns a value by key within the scope, connects the configuration data to an object;\n- \\Magento\\Framework\\Config\\ScopeInterface — identifies the current scope;\n- \\Magento\\Framework\\Config\\FileResolverInterface — identifies a set of files that must be read;\n- \\Magento\\Framework\\Config\\ReaderInterface — reads configuration data;\n- \\Magento\\Framework\\Config\\ConverterInterface — converts a DOM object to an array;\n- \\Magento\\Framework\\Config\\SchemaLocatorInterface — determines the path to validation schemes;\n- \\Magento\\Framework\\Config\\ValidationStateInterface — determines the current validation status.\n\n#### Class groups used to load XML:\n\n- Config is used to access the configuration values;\n- Reader is used to read the file;\n- SchemaLocator stores the path to the validation scheme.\n\n#### How many types of validation for XML configuration ?\n\nMagento 2 provides two types of validation for XML configuration files: validation before a merging and validation after a merging. It can be either the same or different schemes.\nTo create a custom configuration file, you need to create the following elements:\n\n- XSD schema\n- Config PHP file\n- Config reader\n- Schema locator\n- Converter\n\n####  Explain product_types.xml module of Magento_Catalog as an example ?\n\nproduct_types.xml module of Magento_Catalog as an example of a custom configuration file. Each module can add its own product type using the product_types.xml file and these files will be validated and merged.\n\n- We will start with creating an XSD file. product_types.xsd validation scheme is used in Magento_Catalog before merging, product_types_merged.xsd is used for a merged XML file.\n- Create a PHP configuration file to access the data from the file. In our example it is Config.php. To provide access to data from the product_types.xml file, it implements the Magento\\Catalog\\Model\\ProductType\\ConfigInterface interface and all its methods.\n- In Config.php of the constructor, we need to get a reader class. In our case, it is Magento\\Catalog\\Model\\ProductType\\Config\\Reader. This is a small class with the definition of the $_ idAttributes property. In the constructor of the $fileName variable, we define the name of the XML file.\n- Magento\\Catalog\\Model\\ProductType\\Config\\SchemaLocator implements two methods: getSchema and getPerFileSchema and returns the path to merged XSD and ordinary XSD files. In the constructor, we define these paths in the properties of $_ schema and $_ perFileSchema.\n- Creating a converter class. In our example: Magento\\Catalog\\Model\\ProductType\\Config\\Converter implements \\Magento\\Framework\\Config\\ConverterInterface and realizes the convert method, which converts the node’s DOM tree to an array.\nThat is it concerning configuration XML, variables scope and configuration files in Magento 2.\n\n### \u003ca name=\"Step2B1\"\u003eStep 2B1: Setup Module's Backend /System  configuration\u003c/a\u003e\n\n#### What is System  configuration?\nThe system.xml is a configuration file which is used to create configuration fields in Magento 2 System Configuration. You will need this if your module has some settings which the admin needs to set. You can go to Store -\u003e Setting -\u003e Configuration to check how it look like.The magento 2 system configuration page is divided logically in few parts: Tabs, Sections, Groups, Fields.\n\n![](doc/themes14-1.png)\n\n#### How to Set default value?\nEach field in system.xml after create will not have any value. When you call them, you will receive ‘null’ result. So for the module, we will need to set the default value for the field and you will call the value without go to config, set value and save it. This default value will be saved in config.xml which is located in etc folder. Let’s create it for this simple configuration:  [etc/config.xml](etc/config.xml)\n\n```\n\u003cdefault\u003e\n    \u003csection\u003e\n        \u003cgroup\u003e\n            \u003cfield\u003e{value}\u003c/field\u003e\n        \u003c/group\u003e\n    \u003c/section\u003e\n\u003c/default\u003e\n```\n#### How to Get value from configuration ?\nFirst all of let’s save value and flush cache, then you can get saved value from database.\nIn the system.xml, we have added 2 fields: enable and display_text. So the path should be:\nsamplenews/general/enable\nsamplenews/general/display_text\nSimple calling:ex\n```\n$this-\u003escopeConfig-\u003egetValue('samplenews/general/enable', \\Magento\\Store\\Model\\ScopeInterface::SCOPE_STORE);\n$this-\u003escopeConfig-\u003egetValue('samplenews/general/display_text', \\Magento\\Store\\Model\\ScopeInterface::SCOPE_STORE);\n```\n\n\n- Create file[etc/adminhtml/system.xml](etc/adminhtml/system.xml)\n  Purpose: This file will declare your configurations in Stores \u003e Settings \u003e Configuration section) and insert this following code into it:\n\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n      ```\n      \u003c?xml version=\"1.0\"?\u003e\n      \u003cconfig xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"../../../Backend/etc/system_file.xsd\"\u003e\n          \u003csystem\u003e\n              \u003ctab id=\"bdc\" translate=\"label\" sortOrder=\"1\"\u003e\n                  \u003clabel\u003eBDC\u003c/label\u003e\n              \u003c/tab\u003e\n              \u003csection id=\"simplenews\" translate=\"label\" sortOrder=\"1\" showInDefault=\"1\" showInWebsite=\"1\" showInStore=\"1\"\u003e\n                  \u003clabel\u003eSimple News\u003c/label\u003e\n                  \u003ctab\u003ebdc\u003c/tab\u003e\n                  \u003cresource\u003eBDC_SimpleNews::system_config\u003c/resource\u003e\n                  \u003cgroup id=\"general\" translate=\"label\" type=\"text\" sortOrder=\"1\" showInDefault=\"1\" showInWebsite=\"1\" showInStore=\"1\"\u003e\n                      \u003clabel\u003eGeneral Settings\u003c/label\u003e\n                      \u003cfield id=\"enable_in_frontend\" translate=\"label\" type=\"select\" sortOrder=\"1\" showInDefault=\"1\" showInWebsite=\"1\" showInStore=\"1\"\u003e\n                          \u003clabel\u003eEnable in frontend\u003c/label\u003e\n                          \u003csource_model\u003eMagento\\Config\\Model\\Config\\Source\\Yesno\u003c/source_model\u003e\n                      \u003c/field\u003e\n                      \u003cfield id=\"head_title\" translate=\"label comment\" type=\"text\" sortOrder=\"2\" showInDefault=\"1\" showInWebsite=\"1\" showInStore=\"1\"\u003e\n                          \u003clabel\u003eHead title\u003c/label\u003e\n                          \u003ccomment\u003eFill head title of news list page at here\u003c/comment\u003e\n                          \u003cvalidate\u003erequired-entry\u003c/validate\u003e\n                      \u003c/field\u003e\n                      \u003cfield id=\"lastest_news_block_position\" translate=\"label\" type=\"select\" sortOrder=\"3\" showInDefault=\"1\" showInWebsite=\"1\" showInStore=\"1\"\u003e\n                          \u003clabel\u003eLastest news block position\u003c/label\u003e\n                          \u003csource_model\u003eBDC\\SimpleNews\\Model\\System\\Config\\LastestNews\\Position\u003c/source_model\u003e\n                      \u003c/field\u003e\n                  \u003c/group\u003e\n              \u003c/section\u003e\n          \u003c/system\u003e\n      \u003c/config\u003e\n      ```\n  \u003c/details\u003e\n\n#### Note: [System configuration](https://inviqa.com/blog/how-use-system-configuration-and-helpers-magento-2) :\n\nSystem configuration values in Magento 2 are stored in the core_config_data database table, which is exactly the same as in Magento 1. But the xml config files differ.\nThe system.xml is a configuration file which is used to create configuration fields in Magento 2 System Configuration. the system config file is at etc/adminhtml/system.xml\n\nThe system.xml is a configuration file which is used to create configuration fields in Magento 2 System Configuration. You will need this if your module has some settings which the admin needs to set. You can go to Store -\u003e Setting -\u003e Configuration to check how it look like.\n\n\n#### Note:- [MCAD: 5.4 Set up a menu item](https://belvg.com/blog/magento-2-custom-system-configuration.html)\n- How do you add a new menu item to a given tab?\n- How do you add a new tab to the Admin menu?\n\n\n### \u003ca name=\"Step2B2\"\u003eStep 2B2:Create Custom Source Model\u003c/a\u003e\n\n- Create file [Model/System/Config/LastestNews/Position.php](Model/System/Config/LastestNews/Position.php):\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n      ```\n      \u003c?php\n      namespace BDC\\SimpleNews\\Model\\System\\Config\\LastestNews;\n      use Magento\\Framework\\Option\\ArrayInterface;\n      class Position implements ArrayInterface{\n          const LEFT      = 1;\n          const RIGHT     = 2;\n          const DISABLED  = 0;\n\n          /**\n           * Get positions of lastest news block\n           *\n           * @return array\n           */\n          public function toOptionArray(){\n              return [\n                  self::LEFT =\u003e __('Left'),\n                  self::RIGHT =\u003e __('Right'),\n                  self::DISABLED =\u003e __('Disabled')\n              ];\n          }\n      }\n\n      ```\n  \u003c/details\u003e\n\n### \u003ca name=\"Step2B3\"\u003eStep 2B3: Create ACL Role for Config Section\u003c/a\u003e\n\n- Create file [etc/acl.xml](etc/acl.xml)\n  (Purpose: This file will create a role for your configuration section) and insert this following code into it:\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n      ```\n      \u003c?xml version=\"1.0\"?\u003e\n      \u003cconfig xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n      xsi:noNamespaceSchemaLocation=\"../../../../../lib/internal/Magento/Framework/Acl/etc/acl.xsd\"\u003e\n          \u003cacl\u003e\n              \u003cresources\u003e\n                  \u003cresource id=\"Magento_Backend::admin\"\u003e\n                      \u003cresource id=\"Magento_Backend::stores\"\u003e\n                          \u003cresource id=\"Magento_Backend::stores_settings\"\u003e\n                              \u003cresource id=\"Magento_Config::config\"\u003e\n                                  \u003cresource id=\"BDC_SimpleNews::system_config\" title=\"Simple News Section\" /\u003e\n                              \u003c/resource\u003e\n                          \u003c/resource\u003e\n                      \u003c/resource\u003e\n                  \u003c/resource\u003e\n              \u003c/resources\u003e\n          \u003c/acl\u003e\n      \u003c/config\u003e\n      ```\n  \u003c/details\u003e\n\n#### Note:- 5.3 Define / identify basic terms and elements of ACL\n\n- How would you add a new ACL resource to a new entity?  \n- How do you manage the existing ACL hierarchy?  \n\n### \u003ca name=\"Step2B4\"\u003eStep 2B4:  Set some default value for configuration options\u003c/a\u003e\n\n- Create file [etc/config.xml](etc/config.xml) and insert this following code into it:\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n      ```\n      \u003c?xml version=\"1.0\"?\u003e\n      \u003cconfig xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n      xsi:noNamespaceSchemaLocation=\"../../Core/etc/config.xsd\"\u003e\n          \u003cdefault\u003e\n              \u003csimplenews\u003e\n                  \u003cgeneral\u003e\n                      \u003cenable_in_frontend\u003e1\u003c/enable_in_frontend\u003e\n                      \u003chead_title\u003eBDC - Simple News\u003c/head_title\u003e\n                      \u003clastest_news_position\u003e1\u003c/lastest_news_position\u003e\n                  \u003c/general\u003e\n              \u003c/simplenews\u003e\n          \u003c/default\u003e\n      \u003c/config\u003e\n\n      ```\n  \u003c/details\u003e\n\n### \u003ca name=\"Step2B5\"\u003eStep 2B5:  Create a Helper Data class\u003c/a\u003e\n\n\n#### Why need to Create Helper?\nMagento 2, the Helper can be called in controllers, models, views and even in other helpers.\nHelpers can be considered as global and always available elements. They can even be created as single objects’ instances. Besides, they can be called everywhere once you inject them in the class. Helpers are mainly created to offer methods for the most common functionalities. For instance, you can use helpers to build logs in the application of Magento.\nMagento 2 Helper Class includes various functions and methods which are used commonly throughout the application. All the methods which have been declared as Helpers can be called anywhere including file, model, block, controller class or from another helper in Magento 2.\n\n#### What is Helper?\n\nIn the early version of Magento 2, a Helper Factory is available, which enables developers to instantiate helper methods. Besides, you can use the below code to use ObjectManager to instantiate the Helper Factory.\n```\n$object_manager = \\Magento\\Core\\Model\\ObjectManager::getInstance();\n$helper_factory = $object_manager-\u003eget('\\Magento\\Core\\Model\\Factory\\Helper');\n$helper = $helper_factory-\u003eget('\\Magento\\Core\\Helper\\Data');\n```\nHowever, this code still exist some problems. Luckly, a better concept has been introducted which is Dependency Injection in Magento 2.\n\nUsing this concept, the environment will create and provide you an object instead of instantiating it. For instance, if a class is written like the following:\n```\nclass Helper{\n   public function __contruct(Helper $xyz){\n       $this-\u003exyz= $xyz;\n   }\n}\n```\nIn the Helper class constructor, an object of Helper class is auto-created and assigned the reference, $xyz. This is Dependency Injection.\n\nVia this concept, high-value loose coupling modules together concept is provided by Magento 2. If you want to inject it into a specific class, just add an object to the constructor of it. However, you need to remember that you cannot inject one dependency twice.\n\n- Create file: [Helper/Data.php](Helper/Data.php) and insert this following code into it:\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n    ```\n    \u003c?php\n\n    namespace BDC\\SimpleNews\\Helper;\n\n    use Magento\\Framework\\App\\Helper\\AbstractHelper;\n    use Magento\\Framework\\App\\Config\\ScopeConfigInterface;\n    use Magento\\Framework\\App\\Helper\\Context;\n    use Magento\\Store\\Model\\ScopeInterface;\n\n    class Data extends AbstractHelper {\n     const XML_PATH_ENABLED      = 'simplenews/general/enable_in_frontend';\n     const XML_PATH_HEAD_TITLE   = 'simplenews/general/head_title';\n     const XML_PATH_LASTEST_NEWS = 'simplenews/general/lastest_news_block_position';\n\n     /**\n       * @var \\Magento\\Framework\\App\\Config\\ScopeConfigInterface\n       */\n      protected $_scopeConfig;\n\n      /**\n       * @param Context $context\n       * @param ScopeConfigInterface $scopeConfig\n       */\n      public function __construct(\n         Context $context,\n         ScopeConfigInterface $scopeConfig ) {\n         parent::__construct($context);\n         $this-\u003e_scopeConfig = $scopeConfig;\n      }\n\n     /**\n       * Check for module is enabled in frontend\n       *\n       * @return bool\n       */\n     public function isEnabledInFrontend($store = null){\n        return $this-\u003e_scopeConfig-\u003egetValue(\n           self::XML_PATH_ENABLED,\n           ScopeInterface::SCOPE_STORE\n        );\n     }\n\n     /**\n       * Get head title for news list page\n       *\n       * @return string\n       */\n     public function getHeadTitle() {\n        return $this-\u003e_scopeConfig-\u003egetValue(\n           self::XML_PATH_HEAD_TITLE,\n           ScopeInterface::SCOPE_STORE\n        );\n     }\n\n     /**\n       * Get lastest news block position (Left, Right, Disabled)\n       *\n       * @return int\n       */\n     public function getLastestNewsBlockPosition() {\n        return $this-\u003e_scopeConfig-\u003egetValue(\n           self::XML_PATH_LASTEST_NEWS,\n           ScopeInterface::SCOPE_STORE\n        );\n     }\n    }\n\n    ```\n  \u003c/details\u003e\n\n\n\n\n### \u003ca name=\"Step2B6\"\u003eStep 2B6:  Create the menu for Magento backend\u003c/a\u003e\n\n####  Expalin some attributes:id , title, module, parent ,action, resource ? asBelow Code:\n  ```\n  \u003cadd id=\"BDC_SimpleNews::news\" title=\"Manage News\" module=\"BDC_SimpleNews\" sortOrder=\"10\" action=\"bdc_simplenews/news\" resource=\"BDC_SimpleNews::news\" parent=\"BDC_SimpleNews::samplenews\"/\u003e\n  ```\n\n\n  - id attribute is the identifier for this note. It’s a unique string and should follow the format: {Vendor_ModuleName}::{menu_description}.\n  - title attribute is the text which will be shown on the menu bar.\n  - module attribute is defined the module which this menu is belong to.\n  - sortOrder attribute is defined the position of the menu. Lower value will display on top of menu.\n  - parent attribute is an Id of other menu node. It will tell Magento that this menu is a child of another menu. In this example, we have parent=”BDC_SampleNews::samplenews”, so we - know this menu “Manage News” is a child of “Hello World” menu and it will show inside of Hello World menu.\n  - action attribute will define the url of the page which this menu link to. As we talk above, the url will be followed this format {router_name}{controller_folder}{action_name}. - In this example, this menu will link to the module SampleNews, controller News and action Index\n  - resource attribute is used to defined the ACL rule which the admin user must have in order to see and access this menu. We will find more detail about ACL in other topic.\n\n- Create file: [etc/adminhtml/menu.xml](etc/adminhtml/menu.xml) (Purpose: The menu item of your module will be declared here) and insert this following code into it:\n\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n      ```\n      \u003c?xml version=\"1.0\"?\u003e\n      \u003cconfig xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n      xsi:noNamespaceSchemaLocation=\"../../../Backend/etc/menu.xsd\"\u003e\n      \u003cmenu\u003e\n          \u003cadd id=\"BDC_SimpleNews::main_menu\" title=\"Simple News\"\n              module=\"BDC_SimpleNews\" sortOrder=\"20\"\n              resource=\"BDC_SimpleNews::simplenews\" /\u003e\n          \u003cadd id=\"BDC_SimpleNews::add_news\" title=\"Add News\"\n              module=\"BDC_SimpleNews\" sortOrder=\"1\" parent=\"BDC_SimpleNews::main_menu\"\n              action=\"simplenews/news/new\" resource=\"BDC_SimpleNews::manage_news\" /\u003e\n          \u003cadd id=\"BDC_SimpleNews::manage_news\" title=\"Manage News\"\n              module=\"BDC_SimpleNews\" sortOrder=\"2\" parent=\"BDC_SimpleNews::main_menu\"\n              action=\"simplenews/news/index\" resource=\"BDC_SimpleNews::manage_news\" /\u003e\n          \u003cadd id=\"BDC_SimpleNews::configuration\" title=\"Configurations\"\n              module=\"BDC_SimpleNews\" sortOrder=\"3\" parent=\"BDC_SimpleNews::main_menu\"\n              action=\"adminhtml/system_config/edit/section/simplenews\"\n              resource=\"BDC_SimpleNews::configuration\" /\u003e\n      \u003c/menu\u003e\n      \u003c/config\u003e\n      ```\n  \u003c/details\u003e\n\n![MenuLinkAdmin](https://github.com/bdcrops/BDC_SimpleNews/blob/master/doc/adminhtmlMenu.png)\n\n\n### \u003ca name=\"Step2B7\"\u003eStep 2B7: Request Flow Processing / Create backend route file\u003c/a\u003e\n\n#### How to Create Admin route ?\nThis route will be same as the frontend route but you must declare it in adminhtml folder with router id is admin.\nFile: app/code/BDC/SampleNews/etc/adminhtml/routes.xml\n\nThe url of the admin page is the same structure with frontend page, but the admin_area name will be added before route_frontName to recognize this is a admin router. For example, the url of admin cms page:\n\nhttp://example.com/index.php/admin/bdc_samplenews/controller/action\nThe controller action for admin page will be added inside of the folder Controller/Adminhtml. For example for above url:\n```\n{namespace}/{module}/Controller/Adminhtml/{Controller}/{Action}.php\n\n\u003c!--Use router 'admin' for admin route --\u003e\n    \u003crouter id=\"admin\"\u003e\n        \u003c!--Define a custom route with id and frontName --\u003e\n        \u003croute id=\"bdc_samplenews\" frontName=\"bdc_samplenews\"\u003e\n            \u003c!--The module which this route match to--\u003e\n            \u003cmodule name=\"BDC_SampleNews\"/\u003e\n        \u003c/route\u003e\n    \u003c/router\u003e\n  ```\n\n- Create file [etc/adminhtml/routes.xml](etc/adminhtml/routes.xml)\n  Purpose: The router of your module for backend will be declared here insert this following code into it:\n\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n      ```\n      \u003c?xml version=\"1.0\"?\u003e\n\n      \u003cconfig xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n      xsi:noNamespaceSchemaLocation=\"../../../../../../lib/internal/Magento/\n      Framework/App/etc/routes.xsd\"\u003e\n          \u003crouter id=\"admin\"\u003e\n              \u003croute id=\"simplenews\" frontName=\"simplenews\"\u003e\n                  \u003cmodule name=\"BDC_SimpleNews\" /\u003e\n              \u003c/route\u003e\n          \u003c/router\u003e\n      \u003c/config\u003e\n\n      ```\n  \u003c/details\u003e\n\n#### Note:\n- Admin Route: This route will be same as the frontend route but you must declare it in adminhtml folder with router id is admin. /etc/adminhtml/routes.xml\nThe url of the admin page is the same structure with frontend page, but the admin_area name will be added before route_frontName to recognize this is a admin router. For example, the url of admin cms page:\n```\nhttp://example.com/index.php/admin/simplenews/controller/action  {namespace}/{module}/Controller/Adminhtml/{Controller}/{Action}.php\n```\n\n### \u003ca name=\"Step2B8\"\u003eStep 2B8:  Update the acl.xml to add more roles\u003c/a\u003e\n\n#### How to add/Create our module to ACL role?\n As in the Admin Menu and System Configuration article, you saw that we alway have a resource attribute when create it. Now we will register that resources to the system, so Magento can realize and let us set a role for them. To register the resource, we use the acl.xml file which located in\n ```\n app/code/{namespace}/{module}/etc/acl.xml\n ```\n#### ACL Rules for Developers?\nAs a module developer, ACL rules present a few interesting challenges. First, there are several places that you, as a module developer, are expected to add ACL rule checks to your module. A few examples\n\n- Every URL endpoint/controller in the admin application must implement an _ isAllowed method that determines if a user can access the URL endpoint.\n- Every Menu Item in the left hand navigation also has a specific ACL rule that controls whether or not the menu displays for the logged in user. This is often the same rule from _ isAllowed)\n\n- Every configuration field in System -\u003e Configuration has a specific ACL rule that controls whether or not the menu displays\n\nDespite being required fields, there are no hard and fast rules as to how a module developer should setup and structure their own rules. Also, a module developer will likely want additional rules that are specific to their module. This article can’t answer these hard questions for you, but we will show you how to check the current user against a specific ACL rule, look up ID values for existing rules, and how to create your own tree of ACL rules.\n\n#### Explain Magento_Backend::admin,Id Title, sortOrder?\n\n - Magento_Backend::admin: Our resource will be placed as child of Magento_Backend::admin. Each resource will have an Id, title and sortOrder attribute:\n\n- Id: attribute is the identify of this resource. You can use this when define resource in Admin menu, configuration and limit access to your module controller. This is a unique string and should be in this format: Vendor_ModuleName::resource_name.\n- Title: attribute is the label of this resource when showing in resource tree.\n- sortOrder: attribute define the position of this resource in tree.\n\n- Open this file [etc/acl.xml](etc/acl.xml) and modify the source code into here like this:\n\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n      ```\n      \u003c?xml version=\"1.0\"?\u003e\n\n      \u003cconfig xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"../../../../../lib/internal/Magento/\n      Framework/Acl/etc/acl.xsd\"\u003e\n        \u003cacl\u003e\n            \u003cresources\u003e\n                \u003cresource id=\"Magento_Backend::admin\"\u003e\n                    \u003cresource id=\"BDC_SimpleNews::simplenews\" title=\"Simple News\" sortOrder=\"100\"\u003e\n                        \u003cresource id=\"BDC_SimpleNews::add_news\" title=\"Add News\" sortOrder=\"1\" /\u003e\n                        \u003cresource id=\"BDC_SimpleNews::manage_news\" title=\"Manage News\" sortOrder=\"2\" /\u003e\n                        \u003cresource id=\"BDC_SimpleNews::configuration\" title=\"Configurations\" sortOrder=\"3\" /\u003e\n                    \u003c/resource\u003e\n                    \u003cresource id=\"Magento_Backend::stores\"\u003e\n                        \u003cresource id=\"Magento_Backend::stores_settings\"\u003e\n                            \u003cresource id=\"Magento_Config::config\"\u003e\n                                \u003cresource id=\"BDC_SimpleNews::system_config\" title=\"Simple News Section\" /\u003e\n                            \u003c/resource\u003e\n                        \u003c/resource\u003e\n                    \u003c/resource\u003e\n                \u003c/resource\u003e\n            \u003c/resources\u003e\n        \u003c/acl\u003e\n      \u003c/config\u003e\n\n      ```\n  \u003c/details\u003e\n\n### \u003ca name=\"Step2B9\"\u003eStep 2B9:  Create layout for grid\u003c/a\u003e\n\n\n- Create file: [view/adminhtml/layout/simplenews_news_index.xml](view/adminhtml/layout/simplenews_news_index.xml) (Purpose: This file is used to declare grid container block) and insert this following code into it:\n\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n    ```\n    \u003c?xml version=\"1.0\"?\u003e\n\n    \u003cpage xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd\"\u003e\n     \u003cupdate handle=\"formkey\"/\u003e\n     \u003cupdate handle=\"simplenews_news_grid_block\"/\u003e\n     \u003cbody\u003e\n         \u003creferenceContainer name=\"content\"\u003e\n             \u003cblock class=\"BDC\\SimpleNews\\Block\\Adminhtml\\News\"\n                 name=\"bdc_simplenews_news.grid.container\" /\u003e\n         \u003c/referenceContainer\u003e\n     \u003c/body\u003e\n    \u003c/page\u003e\n\n    ```\n  \u003c/details\u003e\n\n### \u003ca name=\"Step2B10\"\u003eStep 2B10:  Create layout for Grid Container\u003c/a\u003e\n\n\n- Create file: app/code/BDC/SimpleNews/view/adminhtml/layout/simplenews_news_grid_block.xml (Purpose: This file is used to declare the content of grid block) and insert this following code into it:\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n      ```\n      \u003c?xml version=\"1.0\"?\u003e\n\n      \u003cpage xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd\"\u003e\n          \u003cbody\u003e\n            \u003creferenceBlock name=\"bdc_simplenews_news.grid.container\"\u003e\n               \u003cblock class=\"Magento\\Backend\\Block\\Widget\\Grid\" name=\"bdc_simplenews_news.grid\"\n                   as=\"grid\"\u003e\n                   \u003carguments\u003e\n                       \u003cargument name=\"id\" xsi:type=\"string\"\u003enewsGrid\u003c/argument\u003e\n                       \u003cargument name=\"dataSource\" xsi:type=\"object\"\u003eBDC\\SimpleNews\\Model\\Resource\\News\\Collection\u003c/argument\u003e\n                       \u003cargument name=\"default_sort\" xsi:type=\"string\"\u003eid\u003c/argument\u003e\n                       \u003cargument name=\"default_dir\" xsi:type=\"string\"\u003edesc\u003c/argument\u003e\n                       \u003cargument name=\"save_parameters_in_session\" xsi:type=\"boolean\"\u003etrue\u003c/argument\u003e\n                       \u003cargument name=\"use_ajax\" xsi:type=\"boolean\"\u003etrue\u003c/argument\u003e\n                       \u003cargument name=\"grid_url\" xsi:type=\"url\" path=\"*/*/grid\"\u003e\n                           \u003cparam name=\"_current\"\u003e1\u003c/param\u003e\n                       \u003c/argument\u003e\n                   \u003c/arguments\u003e\n                      \u003cblock class=\"Magento\\Backend\\Block\\Widget\\Grid\\Massaction\"\n                          name=\"bdc_simplenews_news.grid.massaction\" as=\"grid.massaction\"\u003e\n                          \u003carguments\u003e\n                              \u003cargument name=\"massaction_id_field\" xsi:type=\"string\"\u003eid\u003c/argument\u003e\n                              \u003cargument name=\"form_field_name\" xsi:type=\"string\"\u003enews\u003c/argument\u003e\n                              \u003cargument name=\"options\" xsi:type=\"array\"\u003e\n                                  \u003citem name=\"delete\" xsi:type=\"array\"\u003e\n                                      \u003citem name=\"label\" xsi:type=\"string\" translate=\"true\"\u003eDelete\u003c/item\u003e\n                                      \u003citem name=\"url\" xsi:type=\"string\"\u003e*/*/massDelete\u003c/item\u003e\n                                      \u003citem name=\"confirm\" xsi:type=\"string\" translate=\"true\"\u003eAre you sure you want to delete?\u003c/item\u003e\n                                  \u003c/item\u003e\n                              \u003c/argument\u003e\n                          \u003c/arguments\u003e\n                      \u003c/block\u003e\n                      \u003cblock class=\"Magento\\Backend\\Block\\Widget\\Grid\\ColumnSet\"\n                          name=\"bdc_simplenews_news.grid.columnSet\" as=\"grid.columnSet\"\u003e\n                          \u003carguments\u003e\n                              \u003cargument name=\"rowUrl\" xsi:type=\"array\"\u003e\n                                  \u003citem name=\"path\" xsi:type=\"string\"\u003e*/*/edit\u003c/item\u003e\n                                  \u003citem name=\"extraParamsTemplate\" xsi:type=\"array\"\u003e\n                                      \u003citem name=\"id\" xsi:type=\"string\"\u003egetId\u003c/item\u003e\n                                  \u003c/item\u003e\n                              \u003c/argument\u003e\n                          \u003c/arguments\u003e\n                          \u003cblock class=\"Magento\\Backend\\Block\\Widget\\Grid\\Column\" as=\"id\"\u003e\n                              \u003carguments\u003e\n                                  \u003cargument name=\"header\" xsi:type=\"string\" translate=\"true\"\u003eID\u003c/argument\u003e\n                                  \u003cargument name=\"type\" xsi:type=\"string\"\u003enumber\u003c/argument\u003e\n                                  \u003cargument name=\"id\" xsi:type=\"string\"\u003eid\u003c/argument\u003e\n                                  \u003cargument name=\"index\" xsi:type=\"string\"\u003eid\u003c/argument\u003e\n                              \u003c/arguments\u003e\n                          \u003c/block\u003e\n                          \u003cblock class=\"Magento\\Backend\\Block\\Widget\\Grid\\Column\" as=\"title\"\u003e\n                              \u003carguments\u003e\n                                  \u003cargument name=\"header\" xsi:type=\"string\" translate=\"true\"\u003eTitle\u003c/argument\u003e\n                                  \u003cargument name=\"index\" xsi:type=\"string\"\u003etitle\u003c/argument\u003e\n                              \u003c/arguments\u003e\n                          \u003c/block\u003e\n                          \u003cblock class=\"Magento\\Backend\\Block\\Widget\\Grid\\Column\" as=\"summary\"\u003e\n                              \u003carguments\u003e\n                                  \u003cargument name=\"header\" xsi:type=\"string\" translate=\"true\"\u003eSummary\u003c/argument\u003e\n                                  \u003cargument name=\"index\" xsi:type=\"string\"\u003esummary\u003c/argument\u003e\n                              \u003c/arguments\u003e\n                          \u003c/block\u003e\n                          \u003cblock class=\"Magento\\Backend\\Block\\Widget\\Grid\\Column\" as=\"status\"\u003e\n                              \u003carguments\u003e\n                                  \u003cargument name=\"header\" xsi:type=\"string\" translate=\"true\"\u003eStatus\u003c/argument\u003e\n                                  \u003cargument name=\"index\" xsi:type=\"string\"\u003estatus\u003c/argument\u003e\n                                  \u003cargument name=\"type\" xsi:type=\"string\"\u003eoptions\u003c/argument\u003e\n                                  \u003cargument name=\"options\" xsi:type=\"options\" model=\"BDC\\SimpleNews\\Model\\System\\Config\\Status\"/\u003e\n                              \u003c/arguments\u003e\n                          \u003c/block\u003e\n                          \u003cblock class=\"Magento\\Backend\\Block\\Widget\\Grid\\Column\" as=\"action\" acl=\"BDC_SimpleNews::manage_news\"\u003e\n                              \u003carguments\u003e\n                                  \u003cargument name=\"id\" xsi:type=\"string\"\u003eaction\u003c/argument\u003e\n                                  \u003cargument name=\"header\" xsi:type=\"string\" translate=\"true\"\u003eAction\u003c/argument\u003e\n                                  \u003cargument name=\"type\" xsi:type=\"string\"\u003eaction\u003c/argument\u003e\n                                  \u003cargument name=\"getter\" xsi:type=\"string\"\u003egetId\u003c/argument\u003e\n                                  \u003cargument name=\"filter\" xsi:type=\"boolean\"\u003efalse\u003c/argument\u003e\n                                  \u003cargument name=\"sortable\" xsi:type=\"boolean\"\u003efalse\u003c/argument\u003e\n                                  \u003cargument name=\"index\" xsi:type=\"string\"\u003estores\u003c/argument\u003e\n                                  \u003cargument name=\"is_system\" xsi:type=\"boolean\"\u003etrue\u003c/argument\u003e\n                                  \u003cargument name=\"actions\" xsi:type=\"array\"\u003e\n                                      \u003citem name=\"view_action\" xsi:type=\"array\"\u003e\n                                          \u003citem name=\"caption\" xsi:type=\"string\" translate=\"true\"\u003eEdit\u003c/item\u003e\n                                          \u003citem name=\"url\" xsi:type=\"array\"\u003e\n                                              \u003citem name=\"base\" xsi:type=\"string\"\u003e*/*/edit\u003c/item\u003e\n                                          \u003c/item\u003e\n                                          \u003citem name=\"field\" xsi:type=\"string\"\u003eid\u003c/item\u003e\n                                      \u003c/item\u003e\n                                  \u003c/argument\u003e\n                                  \u003cargument name=\"header_css_class\" xsi:type=\"string\"\u003ecol-actions\u003c/argument\u003e\n                                  \u003cargument name=\"column_css_class\" xsi:type=\"string\"\u003ecol-actions\u003c/argument\u003e\n                              \u003c/arguments\u003e\n                          \u003c/block\u003e\n                      \u003c/block\u003e\n               \u003c/block\u003e\n            \u003c/referenceBlock\u003e\n          \u003c/body\u003e\n      \u003c/page\u003e\n\n      ```\n  \u003c/details\u003e\n\n\n### \u003ca name=\"Step2B11\"\u003eStep 2B11:  Create layout for ajax load\u003c/a\u003e\n\n- Create file: app/code/BDC/SimpleNews/view/adminhtml/layout/simplenews_news_grid.xml (Purpose: This file is used to declare the content of grid when you use ajax to reload the grid) and insert this following code into it:\n\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n    ```\n    \u003c?xml version=\"1.0\"?\u003e\n    \u003cpage xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/layout_generic.xsd\"\u003e\n        \u003cupdate handle=\"formkey\" /\u003e\n        \u003cupdate handle=\"simplenews_news_grid_block\" /\u003e\n        \u003ccontainer name=\"root\"\u003e\n            \u003cblock class=\"Magento\\Backend\\Block\\Widget\\Grid\\Container\" name=\"bdc_simplenews_news.grid.container\" template=\"Magento_Backend::widget/grid/container/empty.phtml\"/\u003e\n        \u003c/container\u003e\n    \u003c/page\u003e\n\n    ```\n  \u003c/details\u003e\n\n### \u003ca name=\"Step2B12\"\u003e Step 2B12:  Create news status option file\u003c/a\u003e\n\n- Create file: app/code/BDC/SimpleNews/Model/System/Config/Status.php (Purpose: This file is used to get News status options) and insert this following code into it:\n\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n      ```\n      \u003c?php\n\n      namespace BDC\\SimpleNews\\Model\\System\\Config;\n\n      use Magento\\Framework\\Option\\ArrayInterface;\n\n      class Status implements ArrayInterface {\n          const ENABLED  = 1;\n          const DISABLED = 0;\n          /**\n           * @return array\n           */\n          public function toOptionArray(){\n              $options = [\n                  self::ENABLED =\u003e __('Enabled'),\n                  self::DISABLED =\u003e __('Disabled')\n              ];\n\n              return $options;\n          }\n      }\n\n      ```\n  \u003c/details\u003e\n\n### \u003ca name=\"Step2B13\"\u003e Step 2B13:  Create News Block for backend\u003c/a\u003e\n- Create file: app/code/BDC/SimpleNews/Block/Adminhtml/News.php (Purpose: This is the block file of grid container) and insert this following code into it:\n\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n      ```\n      \u003c?php\n      namespace BDC\\SimpleNews\\Model\\System\\Config;\n      use Magento\\Framework\\Option\\ArrayInterface;\n      class Status implements ArrayInterface {\n          const ENABLED  = 1;\n          const DISABLED = 0;\n          /**\n           * @return array\n           */\n          public function toOptionArray(){\n              $options = [\n                  self::ENABLED =\u003e __('Enabled'),\n                  self::DISABLED =\u003e __('Disabled')\n              ];\n\n              return $options;\n          }\n      }\n\n      ```\n  \u003c/details\u003e\n\n\n### \u003ca name=\"Step2B14\"\u003eStep 2B14:  Create Status \u003c/a\u003e\n- Create file: app/code/BDC/SimpleNews/Model/System/Config/Status.php (Purpose: check) and insert this following code into it:\n\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n      ```\n      \u003c?php\n\n      namespace BDC\\SimpleNews\\Model\\System\\Config;\n\n      use Magento\\Framework\\Option\\ArrayInterface;\n\n      class Status implements ArrayInterface {\n          const ENABLED  = 1;\n          const DISABLED = 0;\n          /**\n           * @return array\n           */\n          public function toOptionArray(){\n              $options = [\n                  self::ENABLED =\u003e __('Enabled'),\n                  self::DISABLED =\u003e __('Disabled')\n              ];\n\n              return $options;\n          }\n      }\n\n      ```\n  \u003c/details\u003e\n\n### \u003ca name=\"Step2B15\"\u003eStep 2B15:  Create a backend controller file for child action class to extend\u003c/a\u003e\n\n- Create file: app/code/BDC/SimpleNews/Controller/Adminhtml/News.php (Purpose: I use this file as a root controller and the action classes will be extended this controller) and insert this following code into it:\n\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n      ```\n      \u003c?php\n      namespace BDC\\SimpleNews\\Block\\Adminhtml;\n      use Magento\\Backend\\Block\\Widget\\Grid\\Container;\n\n      class News extends Container{\n         /**\n           * Constructor\n           *\n           * @return void\n           */\n         protected function _construct(){\n              $this-\u003e_controller = 'adminhtml_news';\n              $this-\u003e_blockGroup = 'BDC_SimpleNews';\n              $this-\u003e_headerText = __('Manage News');\n              $this-\u003e_addButtonLabel = __('Add News');\n              parent::_construct();\n          }\n      }\n\n      ```\n  \u003c/details\u003e\n\n### \u003ca name=\"Step2B16\"\u003eStep 2B16:  Create Backend Action file Index.php\u003c/a\u003e\n\n- Create file: app/code/BDC/SimpleNews/Controller/Adminhtml/News/Index.php (Purpose: This is the index action) and insert this following code into it:\n\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n      ```\n      \u003c?php\n\n      namespace BDC\\SimpleNews\\Controller\\Adminhtml\\News;\n\n      use BDC\\SimpleNews\\Controller\\Adminhtml\\News;\n\n      class Index extends News{\n          /**\n           * @return void\n           */\n         public function execute(){\n            if ($this-\u003egetRequest()-\u003egetQuery('ajax')) {\n                  $this-\u003e_forward('grid');\n                  return;\n              }\n              /** @var \\Magento\\Backend\\Model\\View\\Result\\Page $resultPage */\n              $resultPage = $this-\u003e_resultPageFactory-\u003ecreate();\n              $resultPage-\u003esetActiveMenu('BDC_SimpleNews::main_menu');\n              $resultPage-\u003egetConfig()-\u003egetTitle()-\u003eprepend(__('Simple News'));\n\n              return $resultPage;\n         }\n      }\n\n      ```\n  \u003c/details\u003e\n\n### \u003ca name=\"Step2B17\"\u003eStep 2B17:  Create another Action for ajax\u003c/a\u003e\n\n- Create file: app/code/BDC/SimpleNews/Controller/Adminhtml/News/Grid.php (Purpose: This is the grid action which is used for loading grid by ajax) and insert this following code into it:\n\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n      ```\n      \u003c?php\n\n      namespace BDC\\SimpleNews\\Controller\\Adminhtml\\News;\n\n      use BDC\\SimpleNews\\Controller\\Adminhtml\\News;\n\n      class Grid extends News {\n         /**\n           * @return void\n           */\n         public function execute() {\n            return $this-\u003e_resultPageFactory-\u003ecreate();\n         }\n      }\n\n      ```\n  \u003c/details\u003e\n\n\n![allNews](https://github.com/bdcrops/BDC_SimpleNews/blob/master/doc/allNews.png)\n\n\n### \u003ca name=\"Step2B18\"\u003e Step 2B18:  Create layout file simplenews_news_edit.xml for edit form\u003c/a\u003e\n- Create file: app/code/BDC/SimpleNews/view/adminhtml/layout/simplenews_news_edit.xml (Purpose: This file is used to declare blocks which used on editing page) and insert this following code into it:\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n    ```\n    \u003c?xml version=\"1.0\"?\u003e\n    \u003cpage xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    layout=\"admin-2columns-left\" xsi:noNamespaceSchemaLocation=\"../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd\"\u003e\n        \u003cbody\u003e\n            \u003creferenceContainer name=\"left\"\u003e\n                \u003cblock class=\"BDC\\SimpleNews\\Block\\Adminhtml\\News\\Edit\\Tabs\"  name=\"bdc_simplenews_news.edit.tabs\"/\u003e\n            \u003c/referenceContainer\u003e\n            \u003creferenceContainer name=\"content\"\u003e\n                \u003cblock class=\"BDC\\SimpleNews\\Block\\Adminhtml\\News\\Edit\"\n                    name=\"bdc_simplenews_news.edit\"/\u003e\n            \u003c/referenceContainer\u003e\n        \u003c/body\u003e\n    \u003c/page\u003e\n    ```\n  \u003c/details\u003e\n\n### \u003ca name=\"Step2B19\"\u003eStep 2B19:  Create the layout for create form\u003c/a\u003e\n\n- Create file: app/code/BDC/SimpleNews/view/adminhtml/layout/simplenews_news_create.xml and insert this following code into it:\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n      ```\n      \u003c?xml version=\"1.0\"?\u003e\n\n      \u003clayout xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n      xsi:noNamespaceSchemaLocation=\"../../../../../Magento/Core/etc/layout_single.xsd\"\u003e\n          \u003cupdate handle=\"simplenews_news_edit\"/\u003e\n      \u003c/layout\u003e\n\n      ```\n  \u003c/details\u003e\n\n### \u003ca name=\"Step2B20\"\u003e Step 2B20:  Create a form container block\u003c/a\u003e\n\n- Create file: app/code/BDC/SimpleNews/Block/Adminhtml/News/Edit.php (Purpose: This is the block file of form container) and insert this following code into it:\n\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n      ```\n      \u003c?php\n\n      namespace BDC\\SimpleNews\\Block\\Adminhtml\\News;\n\n      use Magento\\Backend\\Block\\Widget\\Form\\Container;\n      use Magento\\Backend\\Block\\Widget\\Context;\n      use Magento\\Framework\\Registry;\n\n      class Edit extends Container\n      {\n       /**\n         * Core registry\n         *\n         * @var \\Magento\\Framework\\Registry\n         */\n        protected $_coreRegistry = null;\n\n        /**\n         * @param Context $context\n         * @param Registry $registry\n         * @param array $data\n         */\n        public function __construct(\n            Context $context,\n            Registry $registry,\n            array $data = []\n        ) {\n            $this-\u003e_coreRegistry = $registry;\n            parent::__construct($context, $data);\n        }\n\n        /**\n         * Class constructor\n         *\n         * @return void\n         */\n        protected function _construct()\n        {\n            $this-\u003e_objectId = 'id';\n            $this-\u003e_controller = 'adminhtml_news';\n            $this-\u003e_blockGroup = 'BDC_SimpleNews';\n\n            parent::_construct();\n\n            $this-\u003ebuttonList-\u003eupdate('save', 'label', __('Save'));\n            $this-\u003ebuttonList-\u003eadd(\n                'saveandcontinue',\n                [\n                    'label' =\u003e __('Save and Continue Edit'),\n                    'class' =\u003e 'save',\n                    'data_attribute' =\u003e [\n                        'mage-init' =\u003e [\n                            'button' =\u003e [\n                                'event' =\u003e 'saveAndContinueEdit',\n                                'target' =\u003e '#edit_form'\n                            ]\n                        ]\n                    ]\n                ],\n                -100\n            );\n            $this-\u003ebuttonList-\u003eupdate('delete', 'label', __('Delete'));\n        }\n\n        /**\n         * Retrieve text for header element depending on loaded news\n         *\n         * @return string\n         */\n        public function getHeaderText()\n        {\n            $newsRegistry = $this-\u003e_coreRegistry-\u003eregistry('simplenews_news');\n            if ($newsRegistry-\u003egetId()) {\n                $newsTitle = $this-\u003eescapeHtml($newsRegistry-\u003egetTitle());\n                return __(\"Edit News '%1'\", $newsTitle);\n            } else {\n                return __('Add News');\n            }\n        }\n\n        /**\n         * Prepare layout\n         *\n         * @return \\Magento\\Framework\\View\\Element\\AbstractBlock\n         */\n        protected function _prepareLayout()\n        {\n            $this-\u003e_formScripts[] = \"\n                function toggleEditor() {\n                    if (tinyMCE.getInstanceById('news_content') == null) {\n                        tinyMCE.execCommand('mceAddControl', false, 'news_content');\n                    } else {\n                        tinyMCE.execCommand('mceRemoveControl', false, 'news_content');\n                    }\n                };\n            \";\n\n            return parent::_prepareLayout();\n        }\n      }\n\n      ```\n  \u003c/details\u003e\n\n### \u003ca name=\"Step2B21\"\u003e Step 2B21:  create a block for the left-side tabs\u003c/a\u003e\n\n- Create file: app/code/BDC/SimpleNews/Block/Adminhtml/News/Edit/Tabs.php (Purpose: This file will declare tabs at left column of the editing page) and insert this following code into it:\n\n  \u003cdetails\u003e\u003csummary\u003eSource\u003c/summary\u003e\n\n      ```\n      \u003c?php\n\n      namespace BDC\\SimpleNews\\Block\\Adminhtml\\News;\n\n      use Magento\\Backend\\Block\\Widget\\Form\\Container;\n      use Magento\\Backend\\Block\\Widget\\Context;\n      use Magento\\Framework\\Registry;\n\n      class Edit extends Container\n      {\n         /**\n           * Core registry\n           *\n           * @var \\Magento\\Framework\\Registry\n           */\n          protected $_coreRegistry = null;\n\n          /**\n           * @param Context $context\n           * @param Registry $registry\n           * @param array $data\n           */\n          public function __construct(\n              Context $context,\n              Registry $registry,\n              array $data = []\n          ) {\n              $this-\u003e_coreRegistry = $registry;\n              parent::__construct($context, $data);\n          }\n\n          /**\n           * Class constructor\n           *\n           * @return void\n           */\n          protected function _construct()\n          {\n              $this-\u003e_objectId = 'id';\n              $this-\u003e_controller = 'adminhtml_news';\n              $this-\u003e_blockGroup = 'BDC_SimpleNews';\n\n              parent::_construct();\n\n              $this-\u003ebuttonList-\u003eupdate('save', 'label', __('Save'));\n              $this-\u003ebuttonList-\u003eadd(\n                  'saveandcontinue',\n                  [\n                      'label' =\u003e __('Save and Continue Edit'),\n                      'class' =\u003e 'save',\n                      'data_attribute' =\u003e [\n                          'mage-init' =\u003e [\n                              'button' =\u003e [\n                                  'event' =\u003e 'saveAndContinueEdit',\n                                  'target' =\u003e '#edit_form'\n                              ]\n                          ]\n                      ]\n                  ],\n                  -100\n              );\n              $this-\u003ebuttonList-\u003eupdate('delete', 'label', __('Delete'));\n          }\n\n          /**\n           * Retrieve text for header element depending on loaded news\n           *\n           * @return string\n           */\n          public function getHeaderText()\n          {\n              $newsRegistry = $this-\u003e_coreRegistry-\u003eregistry('simplenews_news');\n              if ($newsRegistry-\u003egetId()) {\n                  $newsTitle = $this-\u003eescapeHtml($newsRegistry-\u003egetTitle());\n                  return __(\"Edit News '%1'\", $newsTitle);\n              } else {\n                  return __('Add News');\n              }\n          }\n\n          /**\n           * Prepare layout\n           *\n           * @return \\Magento\\Framework\\View\\Element\\AbstractBlock\n           */\n          protected function _prepareLayout()\n          {\n              $this-\u003e_formScripts[] = \"\n                  function toggleEditor() {\n                      if (tinyMCE.getInstanceById('news_content') == null) {\n                          tinyMCE.execCommand('mceAddControl', false, 'news_cont","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbdcrops%2Fmodule-simplenews","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbdcrops%2Fmodule-simplenews","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbdcrops%2Fmodule-simplenews/lists"}