سؤال

أنا أعمل على تطبيق ويب من شأنه أن يستفيد من تقنيات AJAX لاتصالات العميل/الخادم ... JSON-RPC على وجه التحديد. يتم استخدام Zend Framework من جانب الخادم ، ويوفر خادم JSON-RPC لطيف أود استخدامه.

هدفي هو المهندس المعماري لنظام يمكن صيانته يعرض أ كبير مجموعة فرعية من وظائف جانب الخادم إلى جانب العميل (JavaScript) ، دون ازدواج رمز غير ضروري. لقد رأيت العديد من منشورات المدونة والبرامج التعليمية حول كيفية استخدام خادم JSON-RPC الخاص بـ ZF (انظر هنا و هنا) ، لكنهم بدوا جميعًا موجهين نحو فضح واجهة برمجة تطبيقات صغيرة قابلة للاستهلاك. يعد تكرار الكود أمرًا شائعًا ، على سبيل المثال منشور مدونة واحد لديه الطريقة التالية المكشوفة:

public static function setTitle($bookId, $title) {
    $book = new Nickel_Model_Book($bookId);
    $book->setTitle($title);
    $book->update();
    return true;
}

لا أحب حقيقة وجود اثنين setTitle طُرق. إذا كان توقيع الطريقة لأحد التغييرات ، فيجب الحفاظ على التزامن الآخر ... يبدو وكأنه كابوس قابلية للصيانة إذا كان واجهة برمجة التطبيقات الخاصة بك واسعة النطاق. يبدو لي أنه يجب أن يكون هناك واحد Book الفصل مع واحد setTitle طريقة.

فكرتي الأولية هي إضافة تعليق توضيحي @export إلى الأساليب/الفصول التي أريد تعرضها. عندما قررت فضح setTitle الطريقة ، أنا فقط أضيف التعليق التوضيحي بدلاً من طريقة جديدة.

إحدى المشكلات المحتملة التي أراها تنطوي على ثبات الكائن. من جانب الخادم ، من المنطقي setTitle لتعيين خاصية عنوان الكائن ... ولكن لا تستمر في قاعدة البيانات حتى update() يسمى. جانب العميل ، الاتصال setTitle يجب أن تؤثر على الفور على قاعدة البيانات. يتمثل أحد الحلول المحتملة في تعديل جميع عمليات الوصول بحيث تأخذ معلمة ثانية اختيارية تدل على التعديل يجب تحديث قاعدة البيانات على الفور:

function setTitle($title, $persist = false) {
    $this->title = $title;

    if ($persist) $this->update();
}

نوع من فئة الوكيل يمكن أن يضمن أن $persist تم تعيين Flag لجميع دعوات RPC من جانب العميل.

مشكلة أخرى هي تسلسل كائنات PHP. من جانب الخادم ، من المنطقي القيام برمدة OO $book->setTitle("foo") اتصل ، ولكن من جانب العميل book.setTitle(1234, "foo") من المنطقي (حيث 1234 هو معرف الكتاب) بسبب عدم وجود حالة. سيكون حلي لهذا هو أن يكون فئة الوكيل المذكورة أعلاه مسؤولاً عن الدوران بطريقة أو بأخرى book.setTitle(1234, "foo") داخل:

$book = new Book();
$book->load(1234);
return $book->setTitle($title);

أشعر أن هذه المشكلة يجب أن تكون قد تمت معالجتها أو مناقشتها من قبل ... لكنني لا أجد العديد من الموارد عبر الإنترنت. هل هذا يبدو وكأنه حل عاقل؟

هل كانت مفيدة؟

المحلول

ما تبحث عنه يسمى طبقة الخدمة.

يجب أن تكون كياناتهم حاويات بيانات بحتة (ما لم تكن تستخدم سجلًا نشطًا) ، يجب عليك فقط فضح طبقة الخدمة الخاصة بك ، وهذا بدوره يصل إلى كياناتهم وطرق كل منهما.

"Your Book class is a Domain Model, you should now create your Service Layer"

سيكون فصل خدمتك شيئًا من هذا القبيل:

class BookService extends Service {

    //...

    public function changeBookTitle( $title, Book $book )
    {
        //verify if the $title is correct and valid
        $book->setTitle( $title );
        $this->methodToGetThePersistenceManager()->save( $book );

        //fire events, create a result object, etc...
    }
}

نصائح أخرى

كنت أفكر في سؤالك لبضع دقائق. إذا كنت ترغب في المحاولة ، وهي في PHP ، يمكنك عمل بعض الأساليب السحرية للنموذج

SET {Property} of {Object}.

يمكنك القيام بذلك من خلال طريقة السحر __call.

وبهذه الطريقة ، لن تضطر إلى تحديد الأساليب بشكل صريح ، لكن الخصائص ستظل محددة.

ستحدد الطريقة السحرية نوع الكائن الذي يجب عليه إنشاءه وأي خاصية يجب تعيينها عليها ثم تستمر.

يجب أن تجد طريقة للتمييز بين المكالمات عن بُعد والمكالمات المحلية على الرغم من أنك لا تستمر عن طريق الخطأ إذا كنت تقوم بإجراء مكالمات مكتبة محلية وتستمر في المكالمات عن بُعد.

أشعر أنني أسيء فهم سؤالك بطريقة أو بأخرى لكنني حاولت.

نحن سوف،

ما تريد القيام به يبدو جيدًا حقًا على الورق ، وتريد أن يكون الكود قابلًا للصيانة ، واعتمادًا على نظامك الفعلي ، قد يكون ما تطلبه آمنًا إلى حد ما ، ومع ذلك فهو يقترب من أن تكون خطيرًا وعرضًا للخطأ.

على أي حال ، ربما يتعين عليك القيام بمعظم هذا بنفسك ، أو فقط أدخل نوعًا من التقاطع لجميع مكالمات الطريقة ، إليك مثال سريع:

class Book {
  public $title = '';
  public $id = 0;
  public function setTitle($string) {
    $this->title = $string;
    echo "title called with $string\n";
  }
  public function twoArgs($arg1,$arg2) {
    echo "Multi-call: $arg1,$arg2\n";
  }
}
class Api {
  public function parse($json) {
    $jsonobj = json_decode($json,true);
    foreach ($jsonobj as $key=>$value) {
      $class_name = $key;
      $obj = new $class_name();
      foreach ($value as $vkey=>$vvalue) {
        if (method_exists($obj,$vkey)) {
          call_user_func_array(array($obj,$vkey),$vvalue);
        } else if (isset($obj->$vkey)) {
          echo "Setting $vkey\n";
          $obj->$vkey = $vvalue;
        }
      }
    }
  }
}

$json = json_encode(array('Book' => array('id' => 1234, 'setTitle' => array('The new title'))));
$api = new Api();
$api->parse($json);
$json = json_encode(array('Book' => array('id' => 1234, 'twoArgs' => array('arg1 :) ', 'arg2 :]'))));
$api->parse($json);

من الواضح أنك تريد إضافة منطق للتعامل مع الإبلاغ المستمر ، والتحميل أو السماح لهم بالمرور في مُنشئ: [args] والتعامل مع ذلك. وما إلى ذلك ، عندما يتعلق الأمر بفضح الوظائف ، فإنك تعرضها في الوثائق ، فهي يمكن الوصول إليها جميعًا طالما أنها وظائف عامة من تلك النقطة على الخ.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top