Pregunta

Estoy trabajando en una aplicación web que va a hacer un uso extensivo de las técnicas AJAX para la comunicación cliente / servidor ... JSON-RPC específicamente. Zend Framework es estar del lado del servidor usado, y ofrece un buen servidor JSON-RPC que me gustaría usar.

Mi objetivo es arquitecto de un sistema mantenible que expone un grande subconjunto de la funcionalidad de servidor para el lado del cliente (JavaScript), sin duplicación de código innecesario. He visto numerosos blogs y tutoriales sobre cómo usar el servidor JSON-RPC de ZF (ver aquí y < a href = "http://sourcecodebean.com/archives/creating-a-json-rpc-service-using-zend-json-server/422" rel = "nofollow"> aquí ), pero todos ellos parecía orientado a la exposición de una pequeña API, consumibles públicamente. La duplicación de código es común, por ejemplo, una entrada de blog tiene el siguiente método expuesto:

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

No me gusta el hecho de que hay dos métodos setTitle. Si la firma del método para uno cambia, el otro tiene que mantenerse en sincronía ... parece como una pesadilla de mantenimiento si su API es extensa. Me parece que debe haber una clase Book, con un método de setTitle.

Mi idea inicial es añadir una anotación de @export bloque de documentación a métodos / clases que quiero expuesto. Cuando decido exponer el método setTitle, acabo de añadir la anotación en lugar de un nuevo método.

Un problema potencial que veo implica la persistencia de objetos. Del lado del servidor, tiene sentido para setTitle para establecer la propiedad título del objeto ... pero no persisten en la base de datos hasta update() se llama. setTitle del lado del cliente, llamando debería afectar inmediatamente a la base de datos. Una posible solución es modificar todos los descriptores de acceso de tal manera que ellos toman un segundo parámetro opcional que significa la modificación debe actualizar la base de datos inmediatamente:

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

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

Una especie de clase de proxy podría asegurar que la bandera $persist se establece para todas las invocaciones RPC del lado del cliente.

Otro problema es la serialización de objetos PHP. Del lado del servidor, tiene sentido hacer una llamada $book->setTitle("foo") de estilo OO, pero book.setTitle(1234, "foo") del lado del cliente tiene sentido (donde 1234 es el identificador del libro), debido a la falta de estado. Mi solución para esto sería tener la clase de proxy antes mencionada sea responsable de alguna manera convertir book.setTitle(1234, "foo") en:

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

Siento que este problema debe haber sido abordado o discutido antes ... pero no estoy encontrando muchos recursos en línea. ¿Esto parece como una solución sensata?

¿Fue útil?

Solución

Lo que usted está buscando se llama capa de servicios .

Sus entidades debe ser puramente contenedores de datos (a menos que estés usando Active Record), sólo se debe exponer a su capa de servicios, y esto a su vez tiene acceso a sus entidades y sus respectivos métodos.

 "Su clase libro es un modelo de dominio, que ahora debe crear su capa de servicios"

Su clase de servicio sería algo como esto:

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...
    }
}

Otros consejos

Yo estaba dándole vueltas a su pregunta durante unos minutos. Si quieres probar, y es en PHP, usted podría hacer algunos métodos mágicos de la forma

Propiedad conjunto {} de {Object}.

Se puede hacer esto a través del método __call magia.

De esa manera usted no tendría que definir explícitamente los métodos, pero las propiedades sería aún así obtener conjunto.

El método mágico sería identificar qué tipo de objeto que tiene que crear una instancia y que la propiedad de conjunto sobre él y luego persistir.

tendría que encontrar alguna manera de diferenciar entre las llamadas a distancia y llamadas locales aunque por lo que no persisten por error si está haciendo llamadas a las bibliotecas locales y que persisten en llamadas remotas.

siento que no he entendido bien su pregunta alguna manera, pero lo intenté.

Bueno,

Lo que están queriendo hacer sonidos muy bien en el papel, y desea que el código sea fácil de mantener, y dependiendo de su sistema actual, con lo que pides, incluso puede ser algo seguro, sin embargo se está poniendo a punto de ser peligroso y propenso a errores.

De todos modos, es probable que tenga que hacer la mayor parte de esto por sí mismo, o simplemente insertar algún tipo de interceptor para todas las llamadas a métodos, aquí hay un ejemplo rápido:

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);

Es evidente que usted querría añadir en la lógica de mango persisten marcar, y la carga o permitir que pasen en un constructor: [args] y manejar eso. etc. Cuando se trata de la exposición de las funciones, que los exponen en la documentación, todos ellos son accesibles, siempre y cuando se trata de funciones públicas partir de ese punto, etc.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top