Rumah > pembangunan bahagian belakang > tutorial php > Kod yang lebih maju sedikit daripada contoh dalam dokumentasi rangka kerja.

Kod yang lebih maju sedikit daripada contoh dalam dokumentasi rangka kerja.

Patricia Arquette
Lepaskan: 2024-12-27 19:06:12
asal
387 orang telah melayarinya

Slightly more advanced code than the example in the frameworks documentation.

Sebagai pengaturcara, saya telah menemui banyak projek selama bertahun-tahun, yang saya warisi, urus, naik taraf, bangunkan dan serahkan. Ramai daripada mereka melibatkan kod spageti atau, sebagaimana ia juga dipanggil, "bola besar lumpur." Isu ini selalunya mempengaruhi projek yang dibina pada beberapa rangka kerja, dengan kod disusun sama seperti contoh dalam dokumentasi rangka kerja.

Malangnya, dokumentasi rangka kerja MVC sering gagal memberi amaran bahawa contoh kod terutamanya bertujuan untuk menggambarkan kefungsian dan tidak sesuai untuk aplikasi dunia sebenar. Akibatnya, projek sebenar sering mengintegrasikan semua lapisan ke dalam kaedah pengawal atau penyampai (dalam kes MVP), yang memproses permintaan (biasanya permintaan HTTP). Jika rangka kerja termasuk Model Objek Komponen, seperti Nette, komponen selalunya merupakan sebahagian daripada pengawal atau penyampai, merumitkan lagi keadaan.

Masalah dengan Struktur Kod Bukan Optimum

Kod projek sedemikian cepat berkembang panjang dan kerumitan. Dalam skrip tunggal, operasi pangkalan data, manipulasi data, permulaan komponen, tetapan templat dan logik perniagaan bercampur. Walaupun pengarang kadang-kadang mengekstrak bahagian fungsi ke dalam perkhidmatan kendiri (biasanya orang tunggal), ini jarang membantu. Projek sebegini menjadi sukar dibaca dan sukar diselenggara.

Dari pengalaman saya, corak reka bentuk piawai jarang digunakan, terutamanya dalam projek yang lebih kecil (5–50 ribu baris kod), seperti aplikasi CRUD mudah untuk perniagaan kecil yang ingin memudahkan pentadbiran. Namun, projek ini boleh mendapat banyak manfaat daripada corak seperti CQRS (Pengasingan Tanggungjawab Pertanyaan Perintah) dan DDD (Reka Bentuk Dipacu Domain).

  1. Permintaan HTTP -> Pengawal/Penyampai
  2. Pengesahan input -> Tukar kepada permintaan
  3. Permintaan -> Perintah
  4. Arahan -> Render/Respons

Saya akan menunjukkan bagaimana pendekatan ini kelihatan menggunakan susunan Nette, Contributte (dengan penyepaduan Symfony Event Dispatcher) dan Nextras ORM.

// Command definition
final class ItemSaveCommand implements Command {
    private ItemSaveRequest $request;

    public function __construct(private Orm $orm) {
        //
    }

    /** @param ItemSaveRequest $request */
    public function setRequest(Request $request): void {
        $this->request = $request;
    }

    public function execute(): void {
        $request = $this->request;

        if ($request->id) {
            $entity = $this->orm->items->getById($request->id);
        } else {
            $entity = new Item();
            $entity->uuid = $request->uuid;
        }

        $entity->data = $request->data;

        $this->orm->persist($entity);
    }
}

// Command Factory
interface ItemSaveCommandFactory extends FactoryService {
    public function create(): ItemSaveCommand;
}

// Request
#[RequestCommandFactory(ItemSaveCommandFactory::class)]
final class ItemSaveRequest implements Request {
    public int|null $id = null;
    public string $uuid;
    public string $data;
}

/**
 * Command execution service
 * Supports transactions and request logging
 */
final class CommandExecutionService implements Service {
    private \DateTimeImmutable $requestedAt;

    public function __construct(
        private Orm $orm,
        private Container $container,
        private Connection $connection,
    ) {
        $this->requestedAt = new \DateTimeImmutable();
    }

    /** @throws \Throwable */
    public function execute(AbstractCommandRequest $request, bool $logRequest = true, bool $transaction = true): mixed {
        $factoryClass = RequestHelper::getCommandFactory($request);
        $factory = $this->container->getByType($factoryClass);

        $cmd = $factory->create();
        $clonedRequest = clone $request;
        $cmd->setRequest($request);

        try {
            $cmd->execute();

            if (!$transaction) {
                $this->orm->flush();
            }

            if (!$logRequest) {
                return;
            }

            $logEntity = RequestHelper::createRequestLog(
                $clonedRequest,
                $this->requestedAt,
                RequestLogConstants::StateSuccess
            );

            if ($transaction) {
                $this->orm->persistAndFlush($logEntity);
            } else {
                $this->orm->persist($logEntity);
            }

            return;
        } catch (\Throwable $e) {
            if ($transaction) {
                $this->connection->rollbackTransaction();
            }

            if (!$logRequest) {
                throw $e;
            }

            $logEntity = RequestHelper::createRequestLog(
                $clonedRequest,
                $this->requestedAt,
                RequestLogConstants::StateFailed
            );

            if ($transaction) {
                $this->orm->persistAndFlush($logEntity);
            } else {
                $this->orm->persist($logEntity);
            }

            throw $e;
        }
    }
}

// Listener for executing commands via Event Dispatcher
final class RequestExecutionListener implements EventSubscriberInterface {
    public function __construct(
        private CommandExecutionService $commandExecutionService
    ) {
        //
    }

    public static function getSubscribedEvents(): array {
        return [
            RequestExecuteEvent::class => 'onRequest'
        ];
    }

    /** @param ExecuteRequestEvent<mixed> $ev */
    public function onRequest(ExecuteRequestEvent $ev): void {
        $this->commandExecutionService->execute($ev->request, $ev->logRequest, $ev->transaction);
    }
}

// Event definition for command execution
final class ExecuteRequestEvent extends Event {
    public function __construct(
        public Request $request,
        public bool $logRequest = true,
        public bool $transaction = true,
    ) {
        // Constructor
    }
}

// Event Dispatcher Facade
final class EventDispatcherFacade {
    public static EventDispatcherInterface $dispatcher;

    public static function set(EventDispatcherInterface $dispatcher): void {
        self::$dispatcher = $dispatcher;
    }
}

// Helper function for simple event dispatching
function dispatch(Event $event): object {
    return EventDispatcherFacade::$dispatcher->dispatch($event);
}

// Usage in Presenter (e.g., in response to a component event)
final class ItemPresenter extends Presenter {
    public function createComponentItem(): Component {
        $component = new Component();
        $component->onSave[] = function (ItemSaveRequest $request) {
            dispatch(new ExecuteRequestEvent($request));
        };

        return $component;
    }
}
Salin selepas log masuk

Penyelesaian ini mempunyai beberapa kelebihan. Logik berkaitan pangkalan data diasingkan daripada MVC/P, menyumbang kepada kebolehbacaan yang lebih baik dan penyelenggaraan yang lebih mudah. Objek permintaan, yang bertindak sebagai pembawa data, sesuai untuk log masuk ke pangkalan data, seperti log peristiwa. Ini memastikan bahawa semua input pengguna yang mengubah suai data disimpan bersama dengan susunan kronologinya. Sekiranya berlaku ralat, log ini boleh disemak dan dimainkan semula jika perlu.

Kelemahan pendekatan ini termasuk hakikat bahawa arahan tidak sepatutnya mengembalikan sebarang data. Oleh itu, jika saya perlu bekerja lebih jauh dengan data yang baru dibuat (cth., hantar ke templat), saya mesti mendapatkannya menggunakan UUIDnya, itulah sebabnya kedua-dua permintaan dan entiti mengandunginya. Kelemahan lain ialah sebarang perubahan pada skema pangkalan data memerlukan pengemaskinian semua permintaan agar sepadan dengan skema baharu, yang boleh memakan masa.

Atas ialah kandungan terperinci Kod yang lebih maju sedikit daripada contoh dalam dokumentasi rangka kerja.. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Artikel terbaru oleh pengarang
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan