Laravel マイページ

Controller

<?php

declare(strict_types=1);

namespace Oms\Http\Controllers\Front;

use Illuminate\Auth\AuthManager;
use Illuminate\Contracts\View\View;
use Illuminate\Database\DatabaseManager;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\URL;
use Oms\Cart\CartFactory;
use Oms\Domain\Front\CustomerAuthentication\CustomerAuthentication;
use Oms\Domain\Front\CustomerMyPage\EditProfile\EditProfile;
use Oms\Domain\Front\CustomerMyPage\EditProfile\ProfileUpdater;
use Oms\Exceptions\OmsException;
use Oms\Http\Controllers\Controller;
use Oms\Http\Requests\Front\MyPage\UpdateProfileRequest;
use Oms\Models\ArticleTag;
use Oms\Models\Customer;
use Oms\Models\Order;
use Oms\Models\Prefecture;
use Oms\Models\Product;
use Oms\UseCase\Order\Exceptions\InvalidOrderException;
use Oms\UseCase\Order\GeneratePdfReceiptAction;
use PDF;

class MyPageController extends Controller
{
    /** @var DatabaseManager */
    protected $dbm;

    /** @var CustomerAuthentication */
    protected $auth;

    /**
     * MyPageController constructor.
     *
     * @param DatabaseManager $databaseManager
     * @param CustomerAuthentication $auth
     */
    public function __construct(
        DatabaseManager $databaseManager,
        CustomerAuthentication $auth
    ) {
        $this->dbm = $databaseManager;
        $this->auth = $auth;
    }

    /**
     * @param EditProfile $domain
     * @param AuthManager $authManager
     *
     * @return View
     */
    public function editProfile(EditProfile $domain, AuthManager $authManager): View
    {
        /** @var Customer $customer */
        $customer = $domain->findCustomer($authManager->guard()->id());
        $posts = Customer::POSTS;
        $jobs = Customer::JOBS;
        $prefectures = Prefecture::all()->pluck('name', 'id')->toArray();
        $sexes = Customer::SEXES;
        $mailmagaFlgs = Customer::MAILMAGA_FLAGS;
        $articleTags = ArticleTag::all()->pluck('name', 'id')->toArray();
        // 定期購読の購入フローに入ったことがある場合は会員情報の必須埋めを促す
        $isNeedProfiling = session()->exists('subscribe.shopping');
        $orders = $customer
            ->orders()
            ->with([
                'paymentType',
                'orderDetails',
            ])
            ->where('status', '<>', Order::DELETED)
            ->orderBy('id', 'desc')
            ->get();

        // お届け先を変更できる注文が最低1件存在する場合、「お届け先変更」ボタンを表示する
        $filteredOrder = $orders->first(function ($order) {
             return $order->canEditDelivery();
        });
        $canEditDelivery = false;
        if (!is_null($filteredOrder)) {
            $canEditDelivery = true;
        }

        return view(
            'front.mypages.profiles.edit',
            compact(
                'customer',
                'posts',
                'jobs',
                'prefectures',
                'sexes',
                'mailmagaFlgs',
                'articleTags',
                'isNeedProfiling',
                'canEditDelivery'
            )
        );
    }

    /**
     * @param UpdateProfileRequest $request
     * @param ProfileUpdater $service
     * @param AuthManager $authManager
     * @param CartFactory $cartFactory
     *
     * @return RedirectResponse
     * @throws \Exception
     */
    public function updateProfile(
        UpdateProfileRequest $request,
        ProfileUpdater $service,
        AuthManager $authManager,
        CartFactory $cartFactory
    ): RedirectResponse {
        $this->dbm->beginTransaction();
        try {
            $service->update($authManager->guard()->id(), $request->all());
            $this->dbm->commit();
        } catch (OmsException $e) {
            $this->dbm->rollBack();
        }

        // [購入フローから会員情報変更へ飛ばされたフラグ]がない場合は更新完了画面
        if (!session()->exists('subscribe.shopping')) {
            return redirect()->route('web.mypage.profile.complete');
        }
        session()->forget('subscribe.shopping');

        // カートの商品を取得
        $cart = $cartFactory->create();
        $cartAll = $cart->all();
        if (count($cartAll) === 0) {
            // カートが空の場合は更新完了画面
            return redirect()->route('web.mypage.profile.complete');
        }

        // 商品ごとの支払方法を取得
        $productIds = $cartAll->pluck('product_id')->toArray();
        $products = Product::find($productIds);
        $product = $products->first();
        if (is_null($product)) {
            // カート内の商品情報が取得できなかった場合は更新完了画面
            return redirect()->route('web.mypage.profile.complete');
        }

        if ($product->productType->isSubscription() || $product->productType->isYearly()) {
            // 定期購読商品・年払い商品の場合は支払い方法選択画面
            return redirect()->route('web.shopping.payment');
        }
        // それ以外はカート画面
        return redirect()->route('web.cart');
    }

    /**
     * @return View
     */
    public function completeProfile(): View
    {
        return view('front.mypages.profiles.complete');
    }

    /**
     * Download receipt pdf files.
     */
    public function receipt(Request $request, GeneratePdfReceiptAction $generatePdfReceiptAction): Response
    {
        $id = (int)$request->route('orderId');
        /** @var \Oms\Models\Order $order */
        $order = Order::query()->findOrFail($id);

        // フロントからのリクエストの場合、
        // 他の顧客の受注の領収書をダウンロードさせない
        $customer = $this->auth->customer();
        if ($customer === null || !$order->isBelongsToCustomer($customer)) {
            abort(404);
        }

        try {
            return $generatePdfReceiptAction->handle($order)
                ->stream('ryoshusyo.pdf');
        } catch (InvalidOrderException $e) {
            Log::error($e->getMessage());
            abort(400);
        }
    }
}

Updator

<?php

declare(strict_types=1);

namespace Oms\Domain\Front\CustomerMyPage\EditProfile;

use Oms\Domain\Front\CustomerMyPage\EditProfile\Entity\Birthday;
use Oms\Domain\Front\CustomerMyPage\EditProfile\Entity\FullName;
use Oms\Models\Interfaces\CustomerInterface;
use Oms\Models\Customer;
use Oms\Models\Prefecture;
use Stripe\Exception\ApiErrorException as StripeApiErrorException;

class ProfileUpdater
{
    /** @var EditProfile */
    protected $domain;

    /**
     * ProfileUpdater constructor.
     *
     * @param EditProfile $editProfile
     */
    public function __construct(EditProfile $editProfile)
    {
        $this->domain = $editProfile;
    }

    /**
     * @param int   $id
     * @param array $data
     *
     * @return CustomerInterface
     * @throws StripeApiErrorException
     */
    public function update(int $id, array $data): CustomerInterface
    {
        /**
         * Customer Attributes
         */
        $customerAttributes = [
            'email' => strtolower($data['email']),
            'name01' => $data['name01'],
            'name02' => $data['name02'],
            'kana01' => $data['kana01'],
            'kana02' => $data['kana02'],
            'company' => $data['company'],
            'unit' => $data['unit'],
            'post' => (int)$data['post'],
            // 性別は個人情報として収集しない方針になったため常に「未回答」として保存する
            'sex' => Customer::SEX_UNSELECTED,
            'mailmaga_flg' => (bool)$data['mailmaga_flg'],
            'job' => (int)$data['job'],
            'birth' => null,
        ];

        $customerAttributes['name'] = (new FullName($data['name01'], $data['name02']))->getFullName();
        if ($data['raw_password']) {
            $customerAttributes['password'] = $data['raw_password'];
        }
        $birthday = (new Birthday($data['year'], $data['month'], $data['day']))->getBirthday();
        if ($birthday) {
            $customerAttributes['birth'] = $birthday;
        }

        /**
         * Address Attributes
         */
        $addressAttributes = [
            'customer_id' => $id,
            'prefecture_id' => $data['prefecture_id'],
            'country' => $data['country'] ?? '日本', // dont update on this feature.
            'postcode' => $data['postcode'],
            'city' => $data['city'],
            'line1' => $data['line1'],
            'tel' => $data['tel'],
            'fax' => $data['fax'],
            'sort' => 1,    // 会員情報の住所は1
            'name01' => $data['name01'],
            'name02' => $data['name02'],
            'kana01' => $data['kana01'],
            'kana02' => $data['kana02'],
            'company' => $data['company'],
            'unit' => $data['unit'],
        ];

        /**
         * Stripe Customer Attributes
         */
        $stripeCustomerAttributes = [
            'email' => strtolower($data['email']),
        ];

        $customer = $this->domain->findCustomer($id);

        /**
         * Tags
         */
        $articleTags = $data['article_tags'] ?? [];

        /**
         * Status
         */
        if ($customer->statusNotYetCustomerPlus()) {
            $customerAttributes['status'] = $customer::STATUS_CUSTOMER_PLUS;
        }

        return $this->domain->update(
            $id,
            $customerAttributes,
            $addressAttributes,
            $stripeCustomerAttributes,
            $articleTags
        );
    }
}

EditProfile

<?php

declare(strict_types=1);

namespace Oms\Domain\Front\CustomerMyPage\EditProfile;

use Oms\Domain\Integrations\BlastMail\BlastMailCustomerIntegrationInterface;
use Oms\Domain\Payments\Stripe\Customer\CustomerUpdation as StripeCustomerUpdation;
use Oms\Models\Interfaces\CustomerInterface;
use Oms\Repositories\Interfaces\AddressRepositoryInterface;
use Oms\Repositories\Interfaces\CustomerRepositoryInterface;
use Stripe\Exception\ApiErrorException as StripeApiErrorException;

class EditProfile
{
    /** @var CustomerRepositoryInterface */
    protected $customerRepository;

    /** @var AddressRepositoryInterface */
    protected $addressRepository;

    /** @var StripeCustomerUpdation */
    protected $stripeCustomerUpdation;

    /** @var BlastMailCustomerIntegrationInterface */
    protected $blastMailCustomerUpsertion;

    public function __construct(
        CustomerRepositoryInterface $customerRepository,
        AddressRepositoryInterface $addressRepository,
        StripeCustomerUpdation $stripeCustomerUpdation,
        BlastMailCustomerIntegrationInterface $blastMailCustomerUpsertion
    ) {
        $this->customerRepository = $customerRepository;
        $this->addressRepository  = $addressRepository;
        $this->stripeCustomerUpdation  = $stripeCustomerUpdation;
        $this->blastMailCustomerUpsertion = $blastMailCustomerUpsertion;
    }

    /**
     * @param int $customerId
     *
     * @return CustomerInterface
     */
    public function findCustomer(int $customerId): CustomerInterface
    {
        return $this->customerRepository->find($customerId)->load(['address', 'articleTags']);
    }

    /**
     * @param int   $id
     * @param array $customerAttributes
     * @param array $addressAttributes
     * @param array $stripeCustomerAttributes
     * @param array $satoriCustomerAttributes
     * @param array $articleTags
     * @return CustomerInterface
     * @throws StripeApiErrorException
     */
    public function update(
        int $id,
        array $customerAttributes,
        array $addressAttributes,
        array $stripeCustomerAttributes,
        array $articleTags = []
    ): CustomerInterface {
        $customer = $this->findCustomer($id);
        $this->customerRepository->update($customer, $customerAttributes);

        // If address is null store address else update.
        if ($customer->address) {
            $this->addressRepository->update($customer->address, $addressAttributes);
        } else {
            $this->addressRepository->store($addressAttributes);
        }

        $customer->articleTags()->sync($articleTags);

        $this->stripeCustomerUpdation->update($customer, $stripeCustomerAttributes);

        // ブラストメール連携
        $customer = $this->findCustomer($customer->id);
        if (config('blastmail.integration_enable')) {
            $this->blastMailCustomerUpsertion->integration($customer);
        }

        return $customer;
    }
}

AppServiceProvider

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        $this->registerInterfaces();
        $this->registerServiceProviders();
        $this->registerFacadeAliases();
    }

    /**
     * Resister Repositories
     *
     * @return void
     */
    public function registerInterfaces()
    {
        $this->app->bind(CustomerInterface::class, function (Application $app) {
            return new Customer();
        });
        $this->app->bind(CustomerRepositoryInterface::class, function (Application $app) {
            return new CustomerRepository(
                $app->make(CustomerFactory::class),
                $app->make(CustomerInterface::class)
            );
        });
        $this->app->bind(AddressRepositoryInterface::class, function (Application $app) {
            return new AddressRepository($app->make(AddressInterface::class));
        });
    }

Repository

<?php

declare(strict_types=1);

namespace Oms\Repositories;

use Oms\Models\Customer;
use Oms\Models\Factory\CustomerFactory;
use Oms\Models\Interfaces\CustomerInterface;
use Oms\Repositories\Exceptions\NotExistsCustomerException;
use Oms\Repositories\Interfaces\CustomerRepositoryInterface;
use Traversable;

class CustomerRepository implements CustomerRepositoryInterface
{
    /** @var CustomerFactory */
    protected $factory;

    /** @var Customer */
    protected $orm;

    /**
     * @inheritdoc
     */
    public function __construct(CustomerFactory $factory, Customer $customer)
    {
        $this->factory = $factory;
        $this->orm     = $customer;
    }

    /**
     * @param int $customerId
     *
     * @return CustomerInterface
     * @throws NotExistsCustomerException
     */
    public function find(int $customerId): CustomerInterface
    {
        $customer = $this->orm->find($customerId);
        if (!$customer) {
            throw new NotExistsCustomerException();
        }

        return $customer;
    }

    /**
     * @inheritdoc
     */
    public function findAll(): Traversable
    {
        return $this->orm->get();
    }

    /**
     * @inheritdoc
     */
    public function store(array $attributes): CustomerInterface
    {
        $customer = app(Customer::class);

        return $this->factory->persist($customer, $attributes);
    }

    /**
     * @param CustomerInterface $customer
     * @param array             $attributes
     *
     * @return CustomerInterface
     * @throws NotExistsCustomerException
     */
    public function update(CustomerInterface $customer, array $attributes): CustomerInterface
    {
        if (!$customer->exists) {
            throw new NotExistsCustomerException();
        }

        $updatedCustomer = $this->factory->persist($customer, $attributes);

        return $this->find($updatedCustomer->id);
    }

    /**
     * @param CustomerInterface $customer
     *
     * @return void
     * @throws NotExistsCustomerException
     */
    public function remove(CustomerInterface $customer)
    {
        if (!$customer->exists) {
            throw new NotExistsCustomerException();
        }

        $customer->delete();
    }

    /**
     * @param $email
     *
     * @return \Illuminate\Database\Eloquent\Model|null|static
     */
    public function findByEmail($email)
    {
        $customer = $this->orm->where('email', $email)->first();
        if (!$customer) {
            throw new NotExistsCustomerException();
        }

        return $customer;
    }
}

factory

<?php

declare(strict_types=1);

namespace Oms\Models\Factory;

use Oms\Models\Customer;
use Oms\Models\Factory\FactoryInterface;

final class CustomerFactory implements FactoryInterface
{
    /** @var Customer */
    private $orm;

    /**
     * CustomerFactory constructor.
     *
     * @param Customer $customer
     */
    public function __construct(Customer $customer)
    {
        $this->orm = $customer;
    }

    /**
     * @param Customer $customer
     * @param array    $attributes
     *
     * @return Customer
     */
    public function persist($customer, array $attributes): Customer
    {
        if (!$customer->exists) {
            return $this->create($attributes);
        }

        return $this->update($customer, $attributes);
    }

    /**
     * @param array $attributes
     *
     * @return Customer
     */
    protected function create(array $attributes): Customer
    {
        $customer = $this->orm->fill($attributes);
        $customer->save();

        return $customer->refresh();
    }

    /**
     * @param Customer $customer
     * @param array    $attributes
     *
     * @return Customer
     */
    protected function update(Customer $customer, array $attributes): Customer
    {
        $customer->fill($attributes)->update();

        return $customer->refresh();
    }
}

パスワードリセット

Controller

<?php

declare(strict_types=1);

namespace Oms\Http\Controllers\Front;

use Illuminate\View\View;
use Illuminate\Database\DatabaseManager;
use Oms\Domain\Front\CustomerPassword\PasswordReset\PasswordUpdater;
use Oms\Exceptions\OmsException;
use Oms\Http\Controllers\Controller;
use Oms\Http\Requests\Front\Forgot\PasswordResetRequest;

class ResetPasswordController extends Controller
{
    /** @var DatabaseManager */
    protected $dbm;

    // cookie name for memoried email
    const MEMORIED_EMAIL_COOKIE_NAME = 'login_email';

    /**
     * Create a new controller instance.
     */
    public function __construct(DatabaseManager $databaseManager)
    {
        $this->dbm = $databaseManager;
    }

    /**
     * Display the password reset view for the given token.
     *
     * @return \Illuminate\View\View
     */
    public function showResetForm(): View
    {
        $memoriedEmail = request()->cookie(static::MEMORIED_EMAIL_COOKIE_NAME);
        return view('front.customers.reset-passwords.form', compact('memoriedEmail'), ['isOneColumn' => true]);
    }

    /**
    * Reset the given customer's password.
    *
    * @param  PasswordResetRequest $request
    * @param  PasswordUpdater $service
    * @return \Illuminate\View\View
    */
    public function reset(
        PasswordResetRequest $request,
        PasswordUpdater $service
    ): View {
        $this->dbm->beginTransaction();
        try {
            $service->update($request['email']);
            $this->dbm->commit();
        } catch (OmsException $e) {
            $this->dbm->rollBack();
        }

        return view('front.customers.reset-passwords.complete', ['isOneColumn' => true]);
    }
}

Updator

<?php

declare(strict_types=1);

namespace Oms\Domain\Front\CustomerPassword\PasswordReset;

use Oms\Models\Interfaces\CustomerInterface;

class PasswordUpdater
{
    /** @var PasswordUpdate */
    protected $domain;

    /**
     * PasswordUpdater constructor.
     *
     * @param PasswordUpdate $passwordUpdate
     */
    public function __construct(PasswordUpdate $passwordUpdate)
    {
        $this->domain = $passwordUpdate;
    }

    /**
     * @param string $email
     *
     * @return CustomerInterface
     */
    public function update(string $email): CustomerInterface
    {
        return $this->domain->update($email);
    }
}

Updation Update

<?php

declare(strict_types=1);

namespace Oms\Domain\Front\CustomerPassword\PasswordReset;

use Illuminate\Contracts\Mail\Mailer;
use Illuminate\Support\Str;
use Oms\Models\Interfaces\CustomerInterface;
use Oms\Repositories\Interfaces\CustomerRepositoryInterface;

class PasswordUpdate
{
    /** @var CustomerRepositoryInterface */
    protected $customerRepository;

    /** @var Mailer */
    protected $mailer;

    /**
     * PasswordUpdate constructor.
     *
     * @param Mailer                        $mailer
     * @param CustomerRepositoryInterface $customerRepository
     */
    public function __construct(
        Mailer $mailer,
        CustomerRepositoryInterface $customerRepository
    ) {
        $this->mailer = $mailer;
        $this->customerRepository = $customerRepository;
    }

    /**
     * Update customer password with ramdom string.
     *
     * @param string $email
     *
     * @return CustomerInterface
     */
    public function update(string $email): CustomerInterface
    {
        $customer = $this->customerRepository->findByEmail($email);

        /**
         * create a reseted password with random string.
         */
        $newPassword = Str::random(13);
        $attributes['password'] = $newPassword;
        $this->customerRepository->update($customer, $attributes);

        /**
         * Send a reseted password mail to customer.
         */
        $this->sendMail($customer, $newPassword);


        return $this->customerRepository->findByEmail($customer->email);
    }

    /**
     * @param CustomerInterface $customer
     * @param string            $newPassword
     */
    protected function sendMail(CustomerInterface $customer, string $newPassword)
    {
        $mailable = new CustomerPasswordResetMail($customer, $newPassword);
        $this->mailer->to($customer->email)->send($mailable);
    }
}

repository

<?php

declare(strict_types=1);

namespace Oms\Repositories;

use Oms\Models\Customer;
use Oms\Models\Factory\CustomerFactory;
use Oms\Models\Interfaces\CustomerInterface;
use Oms\Repositories\Exceptions\NotExistsCustomerException;
use Oms\Repositories\Interfaces\CustomerRepositoryInterface;
use Traversable;

class CustomerRepository implements CustomerRepositoryInterface
{
    /** @var CustomerFactory */
    protected $factory;

    /** @var Customer */
    protected $orm;

    /**
     * @inheritdoc
     */
    public function __construct(CustomerFactory $factory, Customer $customer)
    {
        $this->factory = $factory;
        $this->orm     = $customer;
    }

    /**
     * @param int $customerId
     *
     * @return CustomerInterface
     * @throws NotExistsCustomerException
     */
    public function find(int $customerId): CustomerInterface
    {
        $customer = $this->orm->find($customerId);
        if (!$customer) {
            throw new NotExistsCustomerException();
        }

        return $customer;
    }

    /**
     * @inheritdoc
     */
    public function findAll(): Traversable
    {
        return $this->orm->get();
    }

    /**
     * @inheritdoc
     */
    public function store(array $attributes): CustomerInterface
    {
        $customer = app(Customer::class);

        return $this->factory->persist($customer, $attributes);
    }

    /**
     * @param CustomerInterface $customer
     * @param array             $attributes
     *
     * @return CustomerInterface
     * @throws NotExistsCustomerException
     */
    public function update(CustomerInterface $customer, array $attributes): CustomerInterface
    {
        if (!$customer->exists) {
            throw new NotExistsCustomerException();
        }

        $updatedCustomer = $this->factory->persist($customer, $attributes);

        return $this->find($updatedCustomer->id);
    }

    /**
     * @param CustomerInterface $customer
     *
     * @return void
     * @throws NotExistsCustomerException
     */
    public function remove(CustomerInterface $customer)
    {
        if (!$customer->exists) {
            throw new NotExistsCustomerException();
        }

        $customer->delete();
    }

    /**
     * @param $email
     *
     * @return \Illuminate\Database\Eloquent\Model|null|static
     */
    public function findByEmail($email)
    {
        $customer = $this->orm->where('email', $email)->first();
        if (!$customer) {
            throw new NotExistsCustomerException();
        }

        return $customer;
    }
}

factory

<?php

declare(strict_types=1);

namespace Oms\Models\Factory;

use Oms\Models\Customer;
use Oms\Models\Factory\FactoryInterface;

final class CustomerFactory implements FactoryInterface
{
    /** @var Customer */
    private $orm;

    /**
     * CustomerFactory constructor.
     *
     * @param Customer $customer
     */
    public function __construct(Customer $customer)
    {
        $this->orm = $customer;
    }

    /**
     * @param Customer $customer
     * @param array    $attributes
     *
     * @return Customer
     */
    public function persist($customer, array $attributes): Customer
    {
        if (!$customer->exists) {
            return $this->create($attributes);
        }

        return $this->update($customer, $attributes);
    }

    /**
     * @param array $attributes
     *
     * @return Customer
     */
    protected function create(array $attributes): Customer
    {
        $customer = $this->orm->fill($attributes);
        $customer->save();

        return $customer->refresh();
    }

    /**
     * @param Customer $customer
     * @param array    $attributes
     *
     * @return Customer
     */
    protected function update(Customer $customer, array $attributes): Customer
    {
        $customer->fill($attributes)->update();

        return $customer->refresh();
    }
}

メール生成

<?php

declare(strict_types=1);

namespace Oms\Domain\Front\CustomerPassword\PasswordReset;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Oms\Models\Interfaces\CustomerInterface;

class CustomerPasswordResetMail extends Mailable implements ShouldQueue
{
    use Queueable;
    use SerializesModels;

    /** @var CustomerInterface */
    protected $customer;

    /** @var string */
    protected $newPassword;

    /**
     * CustomerPasswordResetMail constructor.
     *
     * @param CustomerInterface $customer
     * @param string            $newPassword
     */
    public function __construct(CustomerInterface $customer, string $newPassword)
    {
        $this->customer = $customer;
        $this->newPassword = $newPassword;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        $fromAddress = config('oms.site.email.noreply');
        $fromName = '事業構想オンライン';
        $subject = '◆パスワード再発行のお知らせ◆ 事業構想オンライン';
        return $this->view('front.customers.reset-passwords.email')
            ->from($fromAddress, $fromName)
            ->subject($subject)
            ->with([
                'email' => $this->customer->email,
                'newPassword' => $this->newPassword,
            ]);
    }
}

コメント

タイトルとURLをコピーしました