Skip to content

Commit

Permalink
Module Blog - Full Refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
Ruben Romao committed Nov 23, 2023
0 parents commit c7c0589
Show file tree
Hide file tree
Showing 30 changed files with 815 additions and 0 deletions.
54 changes: 54 additions & 0 deletions Api/Data/PostInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php declare(strict_types=1);

namespace Rubenromao\Blog\Api\Data;

/**
* Blog post interface.
* @api
* @since 1.0.0
*/
interface PostInterface
{
const ID = 'id';
const TITLE = 'title';
const CONTENT = 'content';
const CREATED_AT = 'created_at';

/**
* @return int
*/
public function getId();

/**
* @param int $id
* @return $this
*/
public function setId($id);

/**
* @return string
*/
public function getTitle();

/**
* @param string $title
* @return $this
*/
public function setTitle($title);

/**
* @return string
*/
public function getContent();

/**
* @param string $content
* @return $this
*/
public function setContent($content);

/**
* @return string
*/
public function getCreatedAt();
}
37 changes: 37 additions & 0 deletions Api/PostRepositoryInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php declare(strict_types=1);

namespace Rubenromao\Blog\Api;

use Rubenromao\Blog\Api\Data\PostInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;

/**
* Blog post CRUD interface.
* @api
* @since 1.0.0
*/
interface PostRepositoryInterface
{
/**
* @param int $id
* @return PostInterface
* @throws LocalizedException
*/
public function getById(int $id): PostInterface;

/**
* @param PostInterface $post
* @return PostInterface
* @throws LocalizedException
*/
public function save(PostInterface $post): PostInterface;

/**
* @param int $id
* @return bool
* @throws LocalizedException
* @throws NoSuchEntityException
*/
public function deleteById(int $id): bool;
}
21 changes: 21 additions & 0 deletions Controller/Index/Index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php declare(strict_types=1);

namespace Rubenromao\Blog\Controller\Index;

use Magento\Framework\App\Action\HttpGetActionInterface;
use Magento\Framework\Controller\Result\Forward;
use Magento\Framework\Controller\Result\ForwardFactory;

class Index implements HttpGetActionInterface
{
public function __construct(
private ForwardFactory $forwardFactory,
) {}

public function execute(): Forward
{
/** @var Forward $forward */
$forward = $this->forwardFactory->create();
return $forward->setController('post')->forward('list');
}
}
27 changes: 27 additions & 0 deletions Controller/Post/Detail.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php declare(strict_types=1);

namespace Rubenromao\Blog\Controller\Post;

use Magento\Framework\App\Action\HttpGetActionInterface;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\Event\ManagerInterface as EventManager;
use Magento\Framework\View\Result\Page;
use Magento\Framework\View\Result\PageFactory;

class Detail implements HttpGetActionInterface
{
public function __construct(
private PageFactory $pageFactory,
private EventManager $eventManager,
private RequestInterface $request,
) {}

public function execute(): Page
{
$this->eventManager->dispatch('rubenromao_blog_post_detail_view', [
'request' => $this->request,
]);

return $this->pageFactory->create();
}
}
19 changes: 19 additions & 0 deletions Controller/Post/ListAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php declare(strict_types=1);

namespace Rubenromao\Blog\Controller\Post;

use Magento\Framework\App\Action\HttpGetActionInterface;
use Magento\Framework\View\Result\Page;
use Magento\Framework\View\Result\PageFactory;

class ListAction implements HttpGetActionInterface
{
public function __construct(
private PageFactory $pageFactory
) {}

public function execute(): Page
{
return $this->pageFactory->create();
}
}
39 changes: 39 additions & 0 deletions Model/Post.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php declare(strict_types=1);

namespace Rubenromao\Blog\Model;

use Rubenromao\Blog\Api\Data\PostInterface;
use Magento\Framework\Model\AbstractModel;

class Post extends AbstractModel implements PostInterface
{
protected function _construct()
{
$this->_init(ResourceModel\Post::class);
}

public function getTitle()
{
return $this->getData(self::TITLE);
}

public function setTitle($title)
{
return $this->setData(self::TITLE, $title);
}

public function getContent()
{
return $this->getData(self::CONTENT);
}

public function setContent($content)
{
return $this->setData(self::CONTENT, $content);
}

public function getCreatedAt()
{
return $this->getData(self::CREATED_AT);
}
}
55 changes: 55 additions & 0 deletions Model/PostRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php declare(strict_types=1);

namespace Rubenromao\Blog\Model;

use Rubenromao\Blog\Api\Data\PostInterface;
use Rubenromao\Blog\Model\ResourceModel\Post as PostResourceModel;
use Rubenromao\Blog\Api\PostRepositoryInterface;
use Magento\Framework\Exception\CouldNotDeleteException;
use Magento\Framework\Exception\CouldNotSaveException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;

class PostRepository implements PostRepositoryInterface
{
public function __construct(
private PostFactory $postFactory,
private PostResourceModel $postResourceModel,
) {}

public function getById(int $id): PostInterface
{
$post = $this->postFactory->create();
$this->postResourceModel->load($post, $id);

if (!$post->getId()) {
throw new NoSuchEntityException(__('The blog post with "%1" ID doesn\'t exist.', $id));
}

return $post;
}

public function save(PostInterface $post): PostInterface
{
try {
$this->postResourceModel->save($post);
} catch (\Exception $exception) {
throw new CouldNotSaveException(__($exception->getMessage()));
}

return $post;
}

public function deleteById(int $id): bool
{
$post = $this->getById($id);

try {
$this->postResourceModel->delete($post);
} catch (\Exception $exception) {
throw new CouldNotDeleteException(__($exception->getMessage()));
}

return true;
}
}
16 changes: 16 additions & 0 deletions Model/ResourceModel/Post.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php declare(strict_types=1);

namespace Rubenromao\Blog\Model\ResourceModel;

use Magento\Framework\Model\ResourceModel\Db\AbstractDb;

class Post extends AbstractDb
{
const MAIN_TABLE = 'rubenromao_blog_post';
const ID_FIELD_NAME = 'id';

protected function _construct()
{
$this->_init(self::MAIN_TABLE, self::ID_FIELD_NAME);
}
}
15 changes: 15 additions & 0 deletions Model/ResourceModel/Post/Collection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php declare(strict_types=1);

namespace Rubenromao\Blog\Model\ResourceModel\Post;

use Rubenromao\Blog\Model\Post;
use Rubenromao\Blog\Model\ResourceModel\Post as PostResourceModel;
use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection;

class Collection extends AbstractCollection
{
protected function _construct()
{
$this->_init(Post::class, PostResourceModel::class);
}
}
22 changes: 22 additions & 0 deletions Observer/LogPostDetailView.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php declare(strict_types=1);

namespace Rubenromao\Blog\Observer;

use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Psr\Log\LoggerInterface;

class LogPostDetailView implements ObserverInterface
{
public function __construct(
private LoggerInterface $logger,
) {}

public function execute(Observer $observer)
{
$request = $observer->getData('request');
$this->logger->info('blog post detail viewed', [
'params' => $request->getParams(),
]);
}
}
82 changes: 82 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Rubenromao_Blog module

Custom Magento v2.4.6-p3 Blog module to cover Magento 2 concepts and design patterns.

It covers the app structure, how routing & controllers work, how to extend core code,
dependency injection & interfaces, different design patterns and usages, ways to modify the page layout, and understand data management.

The module is not intended to be used in production.
It is a sample module to be used as a reference for Magento 2 development.

The module is based on the [Magento 2.4.6-p3](https://devdocs.magento.com/guides/v2.4/release-notes/bk-release-notes.html) version.

It provides the following functionality:
Custom database table to store blog posts.
Custom model to manage blog posts.
Custom Web API endpoints to create, update, delete, and get blog posts.
Custom admin grid to manage blog posts.
Custom admin form to create and edit blog posts.
Custom frontend page to create a blog post.
Custom frontend page to edit a blog post.
Custom frontend page to delete a blog post.
Custom frontend page to display blog posts.

## Installation details

To install use composer or copy files manually.
It is recommended to install the module in a development environment first.
The

### Install using composer

```
composer require rubenromao/blog
```

Run the following command to enable the module:

```
bin/magento module:enable Rubenromao_Blog
```

You must run the following commands after the module installation using magento-cli

```
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento setup:static-content:deploy -f (optional if you are in developer mode)
bin/magento cache:flush
```

For information about a module installation in Magento 2, see [Enable or disable modules](https://devdocs.magento.com/guides/v2.4/install-gde/install/cli/install-cli-subcommands-enable.html).

## Extensibility

The Rubenromao_Blog module contains extensibility points that you can interact with.
Web API, Service contracts, plugins, events, and observers enable you to extend and customize the Magento application.
You can interact with the following extension points:

Extension developers can interact with the Rubenromao_Blog module. For more information about the Magento extension mechanism, see [Magento plug-ins](https://devdocs.magento.com/guides/v2.4/extension-dev-guide/plugins.html).

[The Magento dependency injection mechanism](https://devdocs.magento.com/guides/v2.4/extension-dev-guide/depend-inj.html) enables you to override the functionality of the Rubenromao_Blog module.

### Layouts

The module introduces layout handles in the `view/frontend/layout` directory.
You can extend these layouts in your custom modules and themes.

For more information about a layout in Magento 2, see the [Layout documentation](https://devdocs.magento.com/guides/v2.4/frontend-dev-guide/layouts/layout-overview.html).

### UI components

You can extend product and category updates using the UI components located in the `view/adminhtml/ui_component` directory.
Or you can extend the UI components located in the `view/base/ui_component` directory.

For information about a UI component in Magento 2, see [Overview of UI components](https://devdocs.magento.com/guides/v2.4/ui_comp_guide/bk-ui_comps.html).

## Additional information

The Rubenromao_Blog module creates a new database table `rubenromao_blog_post` during the installation process.
This table stores blog posts.

For information about significant changes in patch releases, see [Release information](https://devdocs.magento.com/guides/v2.4/release-notes/bk-release-notes.html).
Loading

0 comments on commit c7c0589

Please sign in to comment.