PHPã®ãã¤ã¯ããã¬ã¼ã ã¯ã¼ã¯ãSlim4ãã®ãslim-skeletonãã使ç¨ãã¦ããã£ããã¨

Slim 㯠PHP ã®ãã¤ã¯ããã¬ã¼ã ã¯ã¼ã¯ã§ãã
ã¢ããªã±ã¼ã·ã§ã³éçºã¾ã§ã®ã»ããã¢ãããçæéã§ã§ããããã«ãå
¬å¼ã§ slim-skeleton ãæä¾ãã¦ãã¾ãã
ä»å㯠PHP ã®ãã¼ã¸ã§ã³ 7.2 以éã§ä½¿ç¨å¯è½ãª Slim4 ã使ç¨ãã¦ããã£ããã¨ã®è¨é²ã§ãã
è¨äºã§ä½¿ç¨ãã slim-skeleton ã®ãã¼ã¸ã§ã³ã¯ 4.1.0 ã«ãªãã¾ãã
INDEX
slim-skeleton ã®ã¤ã³ã¹ãã¼ã«
composer å ¬å¼ã¤ã¡ã¼ã¸ã使ã£ã¦slim-skeletonãã¤ã³ã¹ãã¼ã«ãã¦ãã¾ãã
$ docker run --rm -u $(id -u):$(id -g) -v $(pwd):/app composer create-project slim/slim-skeleton
éçºç°å¢ï¼Dockerï¼ã®æºå
slim-skeleton ã®å ¬å¼ãªãã¸ããªãã使ããããã¸ã§ã¯ãã«ã¯ docker-compose.yml ãä»å±ãã¦ãã¾ãã
docker-compose.yml
version: '3.7'
volumes:
logs:
driver: local
services:
slim:
image: php:7-alpine
working_dir: /var/www
command: php -S 0.0.0.0:8080 -t public
environment:
docker: "true"
ports:
- 8080:8080
volumes:
- .:/var/www
- logs:/var/www/logs
ãã®è¨äºã§ã¯ããã©ã«ãæä¾ã® docker-compose.yml ã§å®ç¾©ããã¦ããPHPã®ãã«ãã¤ã³ãµã¼ãã使ç¨ãã¾ãã
以ä¸ã®ã³ãã³ãã§ Docker ãèµ·åãã¾ãã
$ docker-compose up -d
curl ã³ãã³ãã§PHPã®ãã«ãã¤ã³ãµã¼ããèµ·åããã¦ãããã¨ã確èªãã¾ãã
$ curl http://localhost:8080
Hello world!
$ curl http:/localhost:8080/users
{
"statusCode": 200,
"data": [
{
"id": 1,
"username": "bill.gates",
"firstName": "Bill",
"lastName": "Gates"
},
{
"id": 2,
"username": "steve.jobs",
"firstName": "Steve",
"lastName": "Jobs"
},
{
"id": 3,
"username": "mark.zuckerberg",
"firstName": "Mark",
"lastName": "Zuckerberg"
},
{
"id": 4,
"username": "evan.spiegel",
"firstName": "Evan",
"lastName": "Spiegel"
},
{
"id": 5,
"username": "jack.dorsey",
"firstName": "Jack",
"lastName": "Dorsey"
}
]
}
éçºç°å¢ã®æºåã¯ä»¥ä¸ã§ãã
ãµããã£ã¬ã¯ããªéç¨ã§ããã£ããã¨
Slim3 ã¾ã§ã¯ãµããã£ã¬ã¯ããªã§ã·ã¹ãã ãæ±ãå ´åã§ãç¹å¥ãªè¨å®ã¯å¿ è¦ãªãã£ãã®ã§ããã Slim4 ããµããã£ã¬ã¯ããªã§éç¨ããå ´åã«ã¯å¥éè¨å®ãå¿ è¦ã«ãªã£ãããã§ãã
public/index.php
+ $app->setBasePath('/myapp');
ãã¼ãã³ã¼ããå«ãªå ´åã¯ä»¥ä¸ã®é¢æ°ã§è¨å®ããã°ããããã§ãã
$app->setBasePath((function () {
$scriptDir = str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME']));
$uri = (string) parse_url('http://a' . $_SERVER['REQUEST_URI'] ?? '', PHP_URL_PATH);
if (stripos($uri, $_SERVER['SCRIPT_NAME']) === 0) {
return $_SERVER['SCRIPT_NAME'];
}
if ($scriptDir !== '/' && stripos($uri, $scriptDir) === 0) {
return $scriptDir;
}
return '';
})());
Loggerã®è¨å®ã§ããã£ããã¨
ããã©ã«ãã§ã¯ Slim ã®Loggerã使ç¨ãã¦ãããPHPã® error_log() 颿°ã使ç¨ãããããã«ãªã£ã¦ãã¾ãã
Logger ã Monolog ã«å¤æ´ãããã¨ããã¨ãã®è©¦è¡é¯èª¤ã§ãã
Monolog 㯠slim-skeleton ã§ããã¸ã§ã¯ããç«ã¡ä¸ãã㨠vendor ã«æ¢ã«è¿½å ããã¦ããã®ã§ãMonolog ã使ãããã«å¤æ´ãã¾ãã
diff --git a/public/index.php b/public/index.php
index 57722ec..a90b930 100644
--- a/public/index.php
+++ b/public/index.php
@@ -5,6 +5,7 @@ use App\Application\Handlers\HttpErrorHandler;
use App\Application\Handlers\ShutdownHandler;
use App\Application\ResponseEmitter\ResponseEmitter;
use DI\ContainerBuilder;
+use Psr\Log\LoggerInterface;
use Slim\Factory\AppFactory;
use Slim\Factory\ServerRequestCreatorFactory;
@@ -54,7 +55,8 @@ $request = $serverRequestCreator->createServerRequestFromGlobals();
// Create Error Handler
$responseFactory = $app->getResponseFactory();
-$errorHandler = new HttpErrorHandler($callableResolver, $responseFactory);
+$logger = $container->get(LoggerInterface::class);
+$errorHandler = new HttpErrorHandler($callableResolver, $responseFactory, $logger);
// Create Shutdown Handler
$shutdownHandler = new ShutdownHandler($request, $errorHandler, $displayErrorDetails);
@@ -64,7 +66,10 @@ register_shutdown_function($shutdownHandler);
$app->addRoutingMiddleware();
// Add Error Middleware
-$errorMiddleware = $app->addErrorMiddleware($displayErrorDetails, false, false);
+// 第äºå¼æ°ã¨ç¬¬ä¸å¼æ°ã true ã«ãã
+// 第äºå¼æ° $logErrors ã¯ã¨ã©ã¼ãè¨é²ããã
+// 第ä¸å¼æ°ã¯ $logErrorDetails ã¨ã©ã¼è©³ç´°ã表示ããã
+$errorMiddleware = $app->addErrorMiddleware($displayErrorDetails, true, true);
$errorMiddleware->setDefaultErrorHandler($errorHandler);
// Run App & Emit Response
æå³çã«ä¾å¤ãçºçããã¦ãã°ã«åºåããããåä½ã確èªãã¦ã¿ã¾ãã
ListUserAction.php
diff --git a/src/Application/Actions/User/ListUsersAction.php b/src/Application/Actions/User/ListUsersAction.php
index 21b4750..01a1094 100644
--- a/src/Application/Actions/User/ListUsersAction.php
+++ b/src/Application/Actions/User/ListUsersAction.php
@@ -15,6 +15,8 @@ class ListUsersAction extends UserAction
$users = $this->userRepository->findAll();
$this->logger->info("Users list was viewed.");
+ echo EXPECT_NOTICE_ERROR;
+ throw new \RuntimeException('An error was occured.');
return $this->respondWithData($users);
}
$ curl http://localhost:8080/users
<br />
<b>Warning</b>: Use of undefined constant EXPECT_NOTICE_ERROR - assumed 'EXPECT_NOTICE_ERROR' (this will throw an Error in a future version of PHP) in <b>/var/www/src/Application/Actions/User/ListUsersAction.php</b> on line <b>18</b><br />
{
"statusCode": 500,
"error": {
"type": "SERVER_ERROR",
"description": "An error was occured."
}
}{
"statusCode": 500,
"error": {
"type": "SERVER_ERROR",
"description": "ERROR: Use of undefined constant EXPECT_NOTICE_ERROR - assumed 'EXPECT_NOTICE_ERROR' (this will throw an Error in a future version of PHP) on line 18 in file \/var\/www\/src\/Application\/Actions\/User\/ListUsersAction.php."
}
}
slim-skeleton ã®ãã°åºåã¯ç¹ã«è¨å®ãã¦ããªã㨠Docker çµç±ã ã¨æ¨æºåºåã«åºåããã¾ãã 以ä¸ã®ã³ãã³ãã§ãã°ã確èªãã¾ãã
$ docker-compose logs slim
Attaching to slim-skeleton_slim_1
slim_1 | [Mon Jan 4 09:16:38 2021] PHP 7.4.13 Development Server (http://0.0.0.0:8080) started
slim_1 | [Mon Jan 4 09:16:47 2021] 192.168.80.1:38852 Accepted
slim_1 | [2021-01-04T09:16:47.315350+00:00] slim-app.INFO: Users list was viewed. [] {"uid":"40c8453"}
slim_1 | [2021-01-04T09:16:47.316259+00:00] slim-app.ERROR: Slim Application Error Type: RuntimeException Code: 0 Message: An error was occured. File: /var/www/src/Application/Actions/User/ListUsersAction.php Line: 19 Trace: #0 /var/www/src/Application/Actions/Action.php(58): App\Application\Actions\User\ListUsersAction->action() #1 /var/www/vendor/slim/slim/Slim/Handlers/Strategies/RequestResponse.php(43): App\Application\Actions\Action->__invoke(Object(Slim\Psr7\Request), Object(Slim\Psr7\Response), Array) #2 /var/www/vendor/slim/slim/Slim/Routing/Route.php(384): Slim\Handlers\Strategies\RequestResponse->__invoke(Array, Object(Slim\Psr7\Request), Object(Slim\Psr7\Response), Array) #3 /var/www/vendor/slim/slim/Slim/MiddlewareDispatcher.php(81): Slim\Routing\Route->handle(Object(Slim\Psr7\Request)) #4 /var/www/vendor/slim/slim/Slim/MiddlewareDispatcher.php(81): Slim\MiddlewareDispatcher->handle(Object(Slim\Psr7\Request)) #5 /var/www/vendor/slim/slim/Slim/Routing/Route.php(341): Slim\MiddlewareDispatcher->handle(Object(Slim\Psr7\Request)) #6 /var/www/vendor/slim/slim/Slim/Routing/RouteRunner.php(84): Slim\Routing\Route->run(Object(Slim\Psr7\Request)) #7 /var/www/src/Application/Middleware/SessionMiddleware.php(23): Slim\Routing\RouteRunner->handle(Object(Slim\Psr7\Request)) #8 /var/www/vendor/slim/slim/Slim/MiddlewareDispatcher.php(209): App\Application\Middleware\SessionMiddleware->process(Object(Slim\Psr7\Request), Object(Slim\Routing\RouteRunner)) #9 /var/www/vendor/slim/slim/Slim/Middleware/RoutingMiddleware.php(59): class@anonymous->handle(Object(Slim\Psr7\Request)) #10 /var/www/vendor/slim/slim/Slim/MiddlewareDispatcher.php(147): Slim\Middleware\RoutingMiddleware->process(Object(Slim\Psr7\Request), Object(class@anonymous)) #11 /var/www/vendor/slim/slim/Slim/Middleware/ErrorMiddleware.php(107): class@anonymous->handle(Object(Slim\Psr7\Request)) #12 /var/www/vendor/slim/slim/Slim/MiddlewareDispatcher.php(147): Slim\Middleware\ErrorMiddleware->process(Object(Slim\Psr7\Request), Object(class@anonymous)) #13 /var/www/vendor/slim/slim/Slim/MiddlewareDispatcher.php(81): class@anonymous->handle(Object(Slim\Psr7\Request)) #14 /var/www/vendor/slim/slim/Slim/App.php(215): Slim\MiddlewareDispatcher->handle(Object(Slim\Psr7\Request)) #15 /var/www/public/index.php(76): Slim\App->handle(Object(Slim\Psr7\Request)) #16 {main} [] {"uid":"40c8453"}
slim_1 | [Mon Jan 4 09:16:47 2021] 192.168.80.1:38852 [200]: GET /users
slim_1 | [Mon Jan 4 09:16:47 2021] 192.168.80.1:38852 Closing
ä¾å¤ããã°ã«åºåãããããã«ãªãã¾ããããPHP ã® Notice 㨠Warning ããã°ã«åºåããã¦ãã¾ããã
slim-skeleton ã§æä¾ããã¦ãã ShutdownHandler.php ã®ä»¥ä¸ã®å¼æ°ã夿´ããã¨åºåãããããã«ãªãã¾ããã
src/Application/Handlers/ShutdownHandler.php
diff --git a/src/Application/Handlers/ShutdownHandler.php b/src/Application/Handlers/ShutdownHandler.php
index 323f16a..73d5b29 100644
--- a/src/Application/Handlers/ShutdownHandler.php
+++ b/src/Application/Handlers/ShutdownHandler.php
@@ -74,7 +74,7 @@ class ShutdownHandler
}
$exception = new HttpInternalServerErrorException($this->request, $message);
- $response = $this->errorHandler->__invoke($this->request, $exception, $this->displayErrorDetails, false, false);
+ $response = $this->errorHandler->__invoke($this->request, $exception, $this->displayErrorDetails, true, true);
$responseEmitter = new ResponseEmitter();
$responseEmitter->emit($response);
slim_1 | [Mon Jan 4 09:22:06 2021] PHP 7.4.13 Development Server (http://0.0.0.0:8080) started
slim_1 | [Mon Jan 4 09:22:19 2021] 192.168.96.1:34806 Accepted
slim_1 | [2021-01-04T09:22:19.114663+00:00] slim-app.INFO: Users list was viewed. [] {"uid":"c8a86bb"}
slim_1 | [2021-01-04T09:22:19.115963+00:00] slim-app.ERROR: Slim Application Error Type: RuntimeException Code: 0 Message: An error was occured. File: /var/www/src/Application/Actions/User/ListUsersAction.php Line: 19 Trace: #0 /var/www/src/Application/Actions/Action.php(58): App\Application\Actions\User\ListUsersAction->action() #1 /var/www/vendor/slim/slim/Slim/Handlers/Strategies/RequestResponse.php(43): App\Application\Actions\Action->__invoke(Object(Slim\Psr7\Request), Object(Slim\Psr7\Response), Array) #2 /var/www/vendor/slim/slim/Slim/Routing/Route.php(384): Slim\Handlers\Strategies\RequestResponse->__invoke(Array, Object(Slim\Psr7\Request), Object(Slim\Psr7\Response), Array) #3 /var/www/vendor/slim/slim/Slim/MiddlewareDispatcher.php(81): Slim\Routing\Route->handle(Object(Slim\Psr7\Request)) #4 /var/www/vendor/slim/slim/Slim/MiddlewareDispatcher.php(81): Slim\MiddlewareDispatcher->handle(Object(Slim\Psr7\Request)) #5 /var/www/vendor/slim/slim/Slim/Routing/Route.php(341): Slim\MiddlewareDispatcher->handle(Object(Slim\Psr7\Request)) #6 /var/www/vendor/slim/slim/Slim/Routing/RouteRunner.php(84): Slim\Routing\Route->run(Object(Slim\Psr7\Request)) #7 /var/www/src/Application/Middleware/SessionMiddleware.php(23): Slim\Routing\RouteRunner->handle(Object(Slim\Psr7\Request)) #8 /var/www/vendor/slim/slim/Slim/MiddlewareDispatcher.php(209): App\Application\Middleware\SessionMiddleware->process(Object(Slim\Psr7\Request), Object(Slim\Routing\RouteRunner)) #9 /var/www/vendor/slim/slim/Slim/Middleware/RoutingMiddleware.php(59): class@anonymous->handle(Object(Slim\Psr7\Request)) #10 /var/www/vendor/slim/slim/Slim/MiddlewareDispatcher.php(147): Slim\Middleware\RoutingMiddleware->process(Object(Slim\Psr7\Request), Object(class@anonymous)) #11 /var/www/vendor/slim/slim/Slim/Middleware/ErrorMiddleware.php(107): class@anonymous->handle(Object(Slim\Psr7\Request)) #12 /var/www/vendor/slim/slim/Slim/MiddlewareDispatcher.php(147): Slim\Middleware\ErrorMiddleware->process(Object(Slim\Psr7\Request), Object(class@anonymous)) #13 /var/www/vendor/slim/slim/Slim/MiddlewareDispatcher.php(81): class@anonymous->handle(Object(Slim\Psr7\Request)) #14 /var/www/vendor/slim/slim/Slim/App.php(215): Slim\MiddlewareDispatcher->handle(Object(Slim\Psr7\Request)) #15 /var/www/public/index.php(76): Slim\App->handle(Object(Slim\Psr7\Request)) #16 {main} [] {"uid":"c8a86bb"}
slim_1 | [Mon Jan 4 09:22:19 2021] 192.168.96.1:34806 [200]: GET /users
slim_1 | [2021-01-04T09:22:19.117483+00:00] slim-app.ERROR: 500 Internal Server Error Type: Slim\Exception\HttpInternalServerErrorException Code: 500 Message: ERROR: Use of undefined constant EXPECT_NOTICE_ERROR - assumed 'EXPECT_NOTICE_ERROR' (this will throw an Error in a future version of PHP) on line 18 in file /var/www/src/Application/Actions/User/ListUsersAction.php. File: /var/www/src/Application/Handlers/ShutdownHandler.php Line: 76 Trace: #0 [internal function]: App\Application\Handlers\ShutdownHandler->__invoke() #1 {main} [] {"uid":"c8a86bb"}
ãããã¯ã·ã§ã³ç°å¢ã§ã¯ app/settings.php ã® displayErrorsã®å¤ã false ã«ãã¦ã¨ã³ãã¦ã¼ã¶ã¼ã«ã¯ã¨ã©ã¼è©³ç´°ãè¦ããªãå½¢ã«ããã¨æãã¾ããã å°ã£ããã¨ã« displayErrors ã®å¤ã false ã«ããã¨ããã°ã«åºåãããã¨ã©ã¼ã®è©³ç´°ãé表示ã«ãªã£ã¦ãã¾ãã¾ãã
app/settings.php
diff --git a/app/settings.php b/app/settings.php
index 9db7ad1..7b400c9 100644
--- a/app/settings.php
+++ b/app/settings.php
@@ -8,7 +8,7 @@ return function (ContainerBuilder $containerBuilder) {
// Global Settings Object
$containerBuilder->addDefinitions([
'settings' => [
- 'displayErrorDetails' => true, // Should be set to false in production
+ 'displayErrorDetails' => false, // Should be set to false in production
'logger' => [
'name' => 'slim-app',
'path' => isset($_ENV['docker']) ? 'php://stdout' : __DIR__ . '/../logs/app.log',
slim_1 | [2021-01-05T00:44:43.291938+00:00] slim-app.ERROR: 500 Internal Server Error Type: Slim\Exception\HttpInternalServerErrorException Code: 500 Message: An error while processing your request. Please try again later. File: /var/www/src/Application/Handlers/ShutdownHandler.php Line: 76 Trace: #0 [internal function]: App\Application\Handlers\ShutdownHandler->__invoke() #1 {main} Tips: To display error details in HTTP response set "displayErrorDetails" to true in the ErrorHandler constructor. [] {"uid":"e570d39"}
å é¨çã«ã¯ Slim\App::addErrorMiddleware ã¡ã½ãã ã§ Slim\Middleware\ErrorMiddleware ã¤ã³ã¹ã¿ã³ã¹ä½ææã®ã³ã³ã¹ãã©ã¯ã¿ã®ç¬¬4ã第5弿°ã« $logErrors 㨠$logErrorDetails ãæ¸¡ããã¦ãã¾ãã
ErrorMiddleware ã使ç¨ãããã®ã¯ register_shutdown_function() ã§ç»é²ããã ShutdownHandler.php ã®ããã§ ShutdownHandler ã¯ã©ã¹ã®ã³ã³ã¹ãã©ã¯ã¿ã«æ¸¡ãã HttpErrorHandler ã®ã¤ã³ã¹ã¿ã³ã¹ãå®è¡ãã¦ãã¾ãã
HttpErrorHandler ã¯ã©ã¹ã§ã¯ __invoke ã¡ã½ãã ã¯å®è£ ããã¦ãããããã®ç¶æ¿å ã® Slim\Handlers\ErrorMiddleware ã®ããã§ãã°åºåã®æç¡ãæ¯ãåãã¦ããããã§ãã
ãã®è¾ºã slim-skeleton ã®ã¢ããªã±ã¼ã·ã§ã³ã³ã¼ããã Slim4 ã®ã³ã¼ãã«é£ãã ããSlim4 ã®ã³ã¼ããåºåºã¯ã©ã¹ã¨ãªã£ã¦ slim-skeleton ã®åã¯ã©ã¹ãå¼ã³åºãã¦ãããã¨çè§£ãé£ããå°è±¡ã§ãã
ShutdownHandler ã® $displayErrorDetails  ã HttpErrorHandler ã«æ¸¡ãã¦ããã®ã§ããã°åºåã®æã¨ã¬ã¹ãã³ã¹ã®æã¨ã§ã¨ã©ã¼è©³ç´°ã®è¡¨ç¤º/é表示ãåãå¤ãåç §ããããã«ãªã£ã¦ãã¦ãã¬ã¹ãã³ã¹ã«ã¯ã¨ã©ã¼è©³ç´°ãé表示ããã°åºåæã«ã¯ã¨ã©ã¼è©³ç´°ã表示ããã¨ãã£ã Noticeã Warning ã®ç´°ãããã°åºåè¨å®æ¹æ³ãè¦ã¤ãããã¾ããã§ããã
slim-skeleton ã®ãã£ã¬ã¯ããªãã¶ã¤ã³
ããã£ããã¨ã§ã¯ãªãã§ãããå ¬å¼ã® slimphp/slim-skeleton ã®ãã£ã¬ã¯ããªãã¶ã¤ã³ã¯ ADRãã¿ã¼ã³ (Action Domain Responder) ã«æ²¿ã£ã¦ä½ããã¦ããããã§ãã
ShutdownHandler.php 㨠HttpErrorHandler.php 㨠Actions ã坿¥ã«çµ¡ã¿åã£ã¦ããã®ã§ãå¥ã®ãã£ã¬ã¯ããªãã¶ã¤ã³ãã¿ã¼ã³ãæ¡ç¨ããæã«ã¯ slim-skeleton çµç±ã§ããã¸ã§ã¯ãã使ãããã Slim4 ãã¤ã³ã¹ãã¼ã«ãã¦1ããããã¸ã§ã¯ãã使ããæ¹ãããããããã¾ããã
ã¾ã¨ã
Slim4 slim-skeleton ã使ç¨ãã¦ããã£ããã¨ã®ä¸é¨ããç´¹ä»ãã¾ããã
åããããªåé¡ãæ±ãã¦ããæ¹ã®å©ãã«ãªãã°å¹¸ãã§ãã
ãã®è¨äºãæ¸ãã人

- äºæ¥éçºé¨ web application engineer
- 2013å¹´ã«ã¢ã¼ãã£ã¹ã«å ¥ç¤¾ãã·ã¹ãã ã¨ã³ã¸ãã¢ã¨ãã¦ã¢ã¼ãã£ã¹CMSã使ç¨ããWebãµã¤ããåè¨ã·ã¹ãã ã®æ§ç¯ã»ä¿å®ã«æºãããç°å¢æ§ç¯ã好ãã
ãã®å·çè ã®ææ°è¨äº
- 2025å¹´2æ12æ¥WEB2024å¹´æ«ã«ã¢ã«ãã¡çãçºè¡¨ããããããã¬ã¹ UI ã©ã¤ãã©ãª Base UI ã触ã£ã¦ã¿ã
- 2024å¹´12æ12æ¥WEB“éçºè ã®”npmããã±ã¼ã¸ãåå ã§åé¡ã解決ã§ããªãï¼ node_modulesã®ã©ã¤ãã©ãªã«ããããå½ã¦ãæ¹æ³ãæçµææ®µã
- 2024å¹´10æ8æ¥WEBVitestã§ãã©ã¦ã¶ãã¹ããã§ãã!? Browser Modeã試ãã¦ã¿ã
- 2024å¹´8æ21æ¥WEBTypeScriptã®åå®ç¾©ããªãå¤é¨ã©ã¤ãã©ãªã¨monorepoãçµã¿åãããæã«TypeScriptã®ã³ã³ãã¤ã«ã¨ã©ã¼ãçºçãã¦å°ã£ããã¨
é¢é£è¨äº
ææ°è¨äº
FOLLOW US
ææ°ã®æ å ±ããå±ããã¾ã
- facebookã§ãã©ãã¼
- Xã§ãã©ãã¼
- Feedlyã§ãã©ãã¼





