7.3. Subclassing
السابق | فصل 7. Zend_Controller | التالي

## 7.3. Subclassing

### 7.3.1. مقدمة

تم بناء `Zend_Controller` و فى اعتبارنا ان يكون قابل للتمدد بسهولة, سواء عن طريق إن شاء subclasses ترث من الـ class الموجودة او إنشاء classes جديدة تعتمد على الـ interfaces المسمى `Zend_Controller_Router_Interface` و `Zend_Controller_Dispatcher_Interface`.

الأسباب الممكنة لإنشاء router 'موجه' أو dispatcher 'منفذ' جديد , من الممكن أن تكون :

- احيانا يكن نظام التوجيه "routing" الحالى غير مناسب فى بعض الحالات, مثل أن يتم إستخدامه فى موقع ما يستخدم أسلوب أخر لأعادة التوجيه "routing" لا يتوافق مع ميكانيكية عمل الموجه الذى يوفره إطار عمل Zend.

- ربما تريد أن تطبق عملية التوجيه "routing" بشكل او بطريقة مختلفة تماماً , كما قرأت , `Zend_Controller_Router` يتعامل فقط مع الـ URIs, لكن من المحتمل أنك ستود إستخدام الـ MVC pattern لتطوير نوع أخر من البرامج , مثل تطبيقات الـ console , ففى هذه الحالة ستحتاج الى router خاص يقوم بمعالجة مدخلات الـ command line ليتعرف على الـ route المطلوب .

- و ربما تكن الألية التى يوفرها `Zend_Controller_Dispatcher` غير متناسبة مع احتياجك , الإعدادات الأساسية تعتبر أن الـ controllers عبارة عن classes و أن الـ actions عبارة عن methods فى هذه الـ classes , لكن هناك استراتيجيات اخرى يمكن اعتمادها لتنفذ نفس الأداء , على سبيل المثال يمكن اعتبار الـ controllers عبارة عن مجلدات "directories" و الـ actions عبارة عن ملفات داخل هذه المجلدات.

- و ربما تود أن توفر امكانيات و خصائص اضافية يمكن أن ترثها كل الـ controllers لديك , على سبيل المثال , الأعدادات الأساسية لا توفر امكانية أن يتكامل `Zend_Controller_Action` فى عمله تلقائياً مع `Zend_View` , لكن يمكنك أن تنشئ الـ controller الخاص بك الذى يوفر هذه الأمكانية, و ذلك عن طريق الوراثة من `Zend_Controller_Action` , و إستخدامه لن يحتاج إلى أى تعديلات على `Zend_Controller_Router` أو `Zend_Controller_Dispatcher`.

يرجى أن تكن حريص عند محاولة تغيير أجزاء من النظام , تحديداً المنفذ "dispatcher". إحدى ميزات `Zend_Controller` هى أنه يوفر الأمكانيات الأساسية لبناء التطبيقات , لكن ربما إذا تم تغيير جزء كبير من سلوكه الأساسى , ستضيع بعض ميزاته المتوافرة فى حالته الطبيعية. لكن بالطبع هناك احتياجات و حالات مختلفة و لا يمكن أن يقوم حل واحد بتوفير كل هذه الأحتياجات , فلذلك تتوافر لديك الحرية التامة للتعديل إذا احتجتها.

### 7.3.2. التعريفات

عند إنشائك لـ subclasses من اى من الـ classes المتوفرة فى Zend_Controller , يفضل أن تستخدم الأساليب التالية لتعريف الـ classes او اسماء الملفات , اتباعك لهذه الأساليب فى التعريف سيسهل لأى مبرمج أخر يستخدم ZF أن يفهم كيفية عمل مشروعك .

#### 7.3.2.1. Prefix

كل الـ classes المتوفرة داخل ZF تتبع نفس الأسلوب فى التعريف حيث أن كل class يوجد فى بداية اسمه النص "_Zend" , هذا هو ما يسمى الـ prefix , لذلك ننصح أن تقوم بتسمية كل الـ classes التى تنشئها بنفس الأسلوب, على سبيل المثال أن كان إسم الشركة التى تعمل بها هو "Widget" , فيمكنك أن تضع الـ prefix الخاص بأسماء ال classes خاصتك ليكون "_Widget".

#### 7.3.2.2. بنية المجلدات

كل الـ classes الخاصة بـ `Zend_Controller` يتم حفظها فى المجلد library كما يلى :

    /library
      /Zend
        /Controller
          Action.php
          Dispatcher.php
          Router.php

عند القيام بإنشاء subclasses من الـ classes الخاصة بـ `Zend_Controller` , ينصح أن يتم وضع الـ classes الجديدة فى مجلدات لها بنية معرفة تحت اسم الـ prefix الذى تستخدمه , هذا سيسهل ايجاد هذه الـ classes من قبل أى مبرمج يعمل على مشروعك .

على سبيل المثال, إن قامت شركة اسمها widget بإنشاء نسختها المعدلة من الموجه "router" , أن تكن بنية المجلدات بهذا الشكل .

    /library
      /Zend
      /Widget
        /Controller
          Router.php
          README.txt

لاحظ أن فى هذا المثال المجلد `/Widget/Controller` يأتى على نفس هيئة `/Zend/Controller` و هذا الأسلوب يمكنك أن تتبعه إن امكن . فى هذا المثال يوجد `Widget_Controller_Router` و الذى من الممكن أن يكن subclass او بديل لـ `Zend_Controller_Router` و ذلك بتطبيقه للـ interface المسمى `Zend_Controller_Router_Interface`.

أيضاً, لاحظ فى المثال السابق أن الملف `README.txt` تم وضعه فى المجلد `/Widget/Controller` , تنصح ZF أن يتم توفير مستندات توثيقية "documentations" للمشاريع التى تقوم بها إلى جانب اختبارات "tests" للبرنامج عند تقديمه لعميلك, لكن ننصح ايضا ان تضع ملف `README.txt` فى المجلد لتوضيح تغييراتك الجديدة على الـ classes و كيف سيتم التعامل معها .

### 7.3.3. Router Interface

الـ interface المسمى `Zend_Controller_Router_Interface` يوفر تعريف لـ method واحد فقط :

    <?php

      /**
       * @param  Zend_Controller_Dispatcher_Interface
       * @throws Zend_Controller_Router_Exception
       * @return Zend_Controller_Dispatcher_Token|boolean
       */
      public function route(Zend_Controller_Dispatcher_Interface $dispatcher);

    ?>

عملية التوجيه "routing" تحدث مرة واحدة , و ذلك بمجرد استلام النظام للطلب , و يتواجد الـ router لينتج `Zend_Controller_Dispatch_Token` و الذى يحدد الـ controller و الـ action التابع لهذا الـ controller , و هذا يتم تمريره لاحقا الى المنفذ "dispatcher", و فى حالة أنه إذا لم يتم التعرف على بيانات الـ route (ربما نتج عن عملية تحويل غير منطقية ) سيتم ارجاع القيمة FALSE .

بعض الموجهات "routers" تقوم بمعاجلة الطلبات و تحب ان تتأكد من أن الـ token الذى قامت بإنشائه قابل للتنفيذ قبل أن تقوم بإرجاعه , و لهذا السبب يقوم الـ router بإستقبال الـ object handle الخاص بالـ dispatcher كالبراميتر الأساسى للـ method المسمى `()route`, و يقوم الـ dispatcher بتوفير method يسمى `()isDispatchable` للقيام بهذا الأختبار.

### 7.3.4. Dispatcher Interface

سيقوم `Zend_Controller_Front` بإستدعاء الـ router ليستقبل أول dispatch token , و الذى سيتم تمريره إلى الـ dispatcher . سيقوم الـ dispatcher بتنفيذ الـ action (عن طريق إنشاء instance من الـ controller ثم إستدعاء الـ action منه ) , ثم سيقوم بإرجاع اما القيمة FALSE أو dispatch token جديد.

يقوم `Zend_Controller_Front` يإستدعاء الـ dispatcher بشكل متكرر و ذلك إلى أن لا يتم إرجاع dispatch token جديد من الـ dispatcher , و هذا ما يسمى بحلقة التنفيذ او dispatch loop , و هذا الأسلوب يسمح بتنفيذ الـ actions بتسلسل منطقى إلى ان ينتهى كل العمل .

الـ interface المسمى `Zend_Controller_Dispatcher_Interface` يوفر تعريف لإثنين من الـ methods :

    <?php

    /**
     * @param  Zend_Controller_Dispatcher_Token $route
     * @return boolean
     */
    public function isDispatchable(Zend_Controller_Dispatcher_Token $route);

    ?>

يقوم `()isDispatchable` بالتأكد من ان الـ dispatch token الممرر إليه قابل للتنفيذ. و يرجع TRUE إن كان قابل , أو يرجع FALSE إن كان غير قابل للتنفيذ, أما تعريف المعنى المقصود من أن هذا الـ dispatch token قابل للتنفيذ ام لا, متروكة للمبرمج الذى سيستخدم الـ interface , و فى تطبيقنا الأساسى الذى اعتمدناه فى `Zend_Controller_Dispatcher` كانت القابلية للتنفيذ هى ان يكون الملف الذى يحتوى الـ controller موجود , و أن يكون الـ class الخاص بهذا الـ controller موجود فى الملف , و أن الـ method الذى يحمل نفس اسم الـ action موجود داخل هذا الـ class .

    <?php

    /**
     * @param  Zend_Controller_Dispatcher_Token $route
     * @return Zend_Controller_Dispatcher_Token|boolean
     */
    public function dispatch(Zend_Controller_Dispatcher_Token $route);

    ?>

`()dispatch` هو من يقوم بالتفيذ , هذا الـ method يجب أن ينفذ الـ action الخاص بالـ controller , و يجب أن يرجع إما dispatch token جديد ليتم تنفيذه ايضا , أو القيمة FALSE ليعرف انه لا يوجد عمل أخر يجب تنفيذه.

السابق | أعلى | التالي
7.2. البداية | البداية | 7.4. Provided Subclasses