使用 Zend Framework 的 Android RESTful Web 应用程序

2024-01-11

我编写了一个基于 Zend Framework(版本 1.11.11)的 Web 应用程序,我想使用相同的后端代码来编码该应用程序的移动版本(Android)。为了实现这个目标,我想要获取 XML 和 JSON 格式的控制器中每个操作的响应- 适用于基于移动设备的应用程序。

但我面临的问题是:

我的控制器中的每个操作都会返回一个视图变量,然后该变量将由视图脚本进行解释。但我希望每个操作在移动应用程序中返回一个 JSON 数组,在基于浏览器的 Web 应用程序中返回常规/常用的内容(查看变量)。

你们中的任何人都可以给我一个例子来说明如何实现这一目标吗?loginAction() in UsersController.

URL 看起来像:

http://{servername}/service/login

为此,我需要一些关于如何以最有效和正确的方式做到这一点的见解和建议。我在谷歌上搜索答案,但没有找到任何关于如何实现这一目标的好的代码示例或实现示例。我感谢任何帮助和指导。

我这样做的方法是:拥有一个使用参数调用的 API,该参数将解析调用,然后将其卸载到控制器。但编码失败。

到目前为止我拥有的代码:

A UserController with loginAction()(对于登录的用户):

根据我的说法,我应该使用与 UsersController 中的 loginAction 相同的逻辑或更确切地说相同的函数(对于基于网络和基于移动的应用程序),如下所示:

public function loginAction()
  {
// Already logged in
if( Engine_Api::_()->user()->getViewer()->getIdentity() ) {
  $this->view->status = false;
  $this->view->error = Zend_Registry::get('Zend_Translate')->_('You are already signed in.');
  if( null === $this->_helper->contextSwitch->getCurrentContext() ) {
    $this->_helper->redirector->gotoRoute(array(), 'default', true);
  }
  return;
}

// Make form
$this->view->form = $form = new User_Form_Login();
$form->setAction($this->view->url(array('return_url' => null)));
$form->populate(array(
  'return_url' => $this->_getParam('return_url'),
));

// Render
$this->_helper->content
    //->setNoRender()
    ->setEnabled()
    ;

// Not a post
if( !$this->getRequest()->isPost() ) {
  $this->view->status = false;
  $this->view->error = Zend_Registry::get('Zend_Translate')->_('No action taken');
  return;
}

// Form not valid
if( !$form->isValid($this->getRequest()->getPost()) ) {
  $this->view->status = false;
  $this->view->error = Zend_Registry::get('Zend_Translate')->_('Invalid data');
  return;
}

// Check login creds
extract($form->getValues()); // $email, $password, $remember
$user_table = Engine_Api::_()->getDbtable('users', 'user');
$user_select = $user_table->select()
  ->where('email = ?', $email);          // If post exists
$user = $user_table->fetchRow($user_select);

// Get ip address
$db = Engine_Db_Table::getDefaultAdapter();
$ipObj = new Engine_IP();
$ipExpr = new Zend_Db_Expr($db->quoteInto('UNHEX(?)', bin2hex($ipObj->toBinary())));

// Check if user exists
if( empty($user) ) {
  $this->view->status = false;
  $this->view->error = Zend_Registry::get('Zend_Translate')->_('No record of a member with that email was found.');
  $form->addError(Zend_Registry::get('Zend_Translate')->_('No record of a member with that email was found.'));

// Code
  return;
}

// Check if user is verified and enabled
if( !$user->enabled ) {
  if( !$user->verified ) {

   // Code here.
    // End Version 3 authentication

  } else {
    $form->addError('There appears to be a problem logging in. Please reset your password with the Forgot Password link.');

   // Code

    return;
  }
} else { // Normal authentication
  $authResult = Engine_Api::_()->user()->authenticate($email, $password);
  $authCode = $authResult->getCode();
  Engine_Api::_()->user()->setViewer();

  if( $authCode != Zend_Auth_Result::SUCCESS ) {
    $this->view->status = false;
    $this->view->error = Zend_Registry::get('Zend_Translate')->_('Invalid credentials');
    $form->addError(Zend_Registry::get('Zend_Translate')->_('Invalid credentials supplied'));

   //Code
    return;
  }
}

// -- Success! --

// Register login
$loginTable = Engine_Api::_()->getDbtable('logins', 'user');
$loginTable->insert(array(
  'user_id' => $user->getIdentity(),
  'email' => $email,
  'ip' => $ipExpr,
  'timestamp' => new Zend_Db_Expr('NOW()'),
  'state' => 'success',
  'active' => true,
));
$_SESSION['login_id'] = $login_id = $loginTable->getAdapter()->lastInsertId();
$_SESSION['user_id'] = $user->getIdentity();

// Some code.

// Do redirection only if normal context
if( null === $this->_helper->contextSwitch->getCurrentContext() ) {
  // Redirect by form
  $uri = $form->getValue('return_url');
  if( $uri ) {
    if( substr($uri, 0, 3) == '64-' ) {
      $uri = base64_decode(substr($uri, 3));
    }
    if($viewer->is_vendor) {
        return $this->_helper->redirector->gotoRoute(array('module' => 'user' ,'controller' => 'vendors', 'action' => 'mydeals'), 'vendor_mydeals', true);
    } else {
        return $this->_helper->redirector->gotoRoute(array('action' => 'index'), 'user_searchquery', true);
    }
    //return $this->_redirect($uri, array('prependBase' => false));
  }

  return $this->_helper->redirector->gotoRoute(array('action' => 'index'), 'user_searchquery', true);
}

}

所以我想用上面的loginAction()即使对于基于移动的应用程序也是如此。

接下来,我有一个名为 Service_Api 的类,具有多种功能。下面是我现在根据 id 获取用户的函数。

private function getUser(array $params)
{
    $userData = array();
    $usersTable = Engine_Api::_()->getDbtable('users', 'user'); 
    $select = $usersTable->select()->where('user_id = ?', $params['user']);

    $user = $usersTable->findOne($params['user']);
    if($user) {
        $userData = $user->exportToArray();
    }

    return Zend_Json_Encoder::encode($userData);
}

同样,我想要一个用于登录的loginAction。loginAction()看看我如何仅获取移动应用程序的 JSON 值(例如来自数据库的用户值以及登录成功/失败的成功/失败)。

我想要一个 RESTful URL。

所以我的网址看起来像:

http://{servername}/service/login
http://{servername}/service/groups/list etc.

我有一个名为 ServiceController 的控制器,其登录操作如下:

public function loginAction()
{
    $this->_helper->viewRenderer->setNoRender();
    $this->_helper->layout->disableLayout(true);
    /*
     * Fetch Parameters and Parameter Keys
     * We don't need the controller or action!
     */
    $params = $this->_getAllParams();
    unset($params['controller']);
    unset($params['action']);
    unset($params['module']);
    unset($params['rewrite']);
    $paramKeys = array_keys($params);

    /*
     * Whitelist filter the Parameters
     */
    Zend_Loader::loadClass('Zend_Filter_Input');
    $filterParams = new Zend_Filter_Input($params);

    /*
     * Build a request array, with method name to call
     * on handler class for REST server indexed with
     * 'method' key.
     *
     * Method name is constructed based on valid parameters.
     */
    $paramKeysUc = array();
    foreach($paramKeys as $key)
    {
        $paramKeysUc[] = ucfirst($key);
    }

    $methodName = 'getBy' . implode('', $paramKeysUc);
    $request = array(
        'method'=>$methodName   
    );

    /*
     * Filter parameters as needed and add them all to the
     * $request array if valid.
     */
    foreach($paramKeys as $key)
    {
        switch($key)
        {
            case'tag':
                $request[$key] = $filterParams->testAlnum($key);
                break;
            default:
                $request[$key] = $params[$key];
        }
        if(!$request[$key])
        {
            // need better handling of filter errors for a real webservice…
            throw new Exception($request[$key] . ' contained invalid data');
        }
    }

    /*
     * Setup Zend_Rest_Server
     */
    require_once 'Zend/Rest/Server.php';

    $server = new Zend_Rest_Server;
    $server->setClass('Service_API');
    echo $server->handle($request);
}

但这是使用单独的控制器操作。

任何帮助表示赞赏。

谢谢。 阿比拉什


禁用布局适用于 JSON,但它不允许您根据请求的格式(XML、JSON 等)将请求重定向到良好的控制器。

从那里,如何根据请求的格式决定调用哪些操作?

Ajax 上下文

Use Ajax上下文 http://framework.zend.com/manual/en/zend.controller.actionhelpers.html#zend.controller.actionhelpers.contextswitch在你的控制器中_init() method:

$ajaxContext = $this->_helper->getHelper('AjaxContext');
$ajaxContext->addActionContext('login', 'json')
            ->addActionContext('login', 'xml')
            ->initContext();

这将有效地将您的 XML 请求重定向到与您的 JSON 请求相同的操作。

如何判断应该使用哪种格式?只需添加?format=xml or /format/xml(或 json)到 URL 参数。您的 URL 更愿意看起来像这样:http://{servername}/service/login/format/json.

从您的操作中,如何知道请求的是哪种格式?您无需做任何事情,AjaxContext 已经处理好一切。

如果是 JSON 请求:

JSON。 JSON 上下文将“Content-Type”响应标头设置为 'application/json',视图脚本后缀为'json.phtml'。

但是,默认情况下不需要视图脚本。它会简单地 序列化所有视图变量,并立即发出 JSON 响应。

如果是 XML 请求:

将视图后缀更改为“xml.phtml”(或者,如果您使用备用 查看后缀,'xml.[您的后缀]')。

请注意,使用 AjaxContext,响应标头是将自动设置根据要求的响应格式。

意识到这一点,你不需要使用Zend_Json_Encoder不再了。

如果你想了解更多关于 RESTful API 的信息,我读过一篇非常有趣的文章Matthew Weier O'Phinney 撰写的 ppt 幻灯片 http://www.slideshare.net/weierophinney/architecting-ajax-applications-with-zend-framework(目前是采埃孚的项目负责人),我绝对推荐它。

另一件事,您的应用程序似乎不尊重瘦控制器和胖模型约定 http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-modelZend Framework 推荐的,我相信如果你遵循这个原则,它会让你的事情变得更加清晰。还有,你的loginAction()只会从模型中获取成功或失败消息,使用我上面描述的方法可以很容易地将其转换为 JSON 或 XML。

RESTful API

为了了解请求是 GET 请求还是 POST 请求,请在控制器中使用以下方法:

  • $this->_getAllParams();或 $this->getRequest()->getParams();` 将捕获所有参数、POST 和 GET。
  • $this->getRequest()->getPost()检索 POST 参数。
  • $this->getRequest()->getQuery()检索 GET 参数。

要确定请求类型,您可以使用以下方法:

  • isGet()
  • isPost()
  • isPut()
  • isDelete()

更多信息在手册中 http://framework.zend.com/manual/en/zend.controller.request.html#zend.controller.request.http.method.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Zend Framework 的 Android RESTful Web 应用程序 的相关文章

随机推荐

  • Socket.Shutdown 抛出 SocketException

    我正在尝试为我的项目实现异步套接字 这是代码 public void Start int listeningPort var ipHostInfo Dns Resolve Dns GetHostName var ipAddress ipHo
  • 正则表达式蛋白质消化

    因此 我正在用一种酶 出于你的好奇心 Asp N 消化蛋白质序列 该酶在单字母编码序列中 B 或 D 编码的蛋白质之前进行切割 我的实际分析使用String scan用于捕获 我试图找出为什么以下正则表达式不能正确消化它 w BD b 先行
  • 如何在vscode终端中将i386 arch更改为arm64?

    如何在vscode终端中将i386 arch更改为arm64 m2 Pro 硅 我问因为yarn and npm无法在 vscode 终端中工作 但在外部终端 iterm2 终端 中完美工作 vscode 终端 https i stack
  • Rust 链接器寻找 LIB,而不是 DLL

    我正在 Windows 上尝试 Rust 我的代码声明并调用外部库中的函数 声明是这样的 link name Rvea0326nc 64 extern C fn WeibullSpeedProbability wa f32 wk f32 q
  • 无休止的动画、requestAnimationFrame 和调用堆栈限制

    我正在开发一个小项目 该项目使用 Twitter 流 API 并从中制作一些画布动画 鉴于 Twitter 流 API 没有结束 动画可能会无限期地继续下去 问题就在于此 requestAnimationFrame似乎是通过递归进行操作的
  • 使用 shell 迭代文件

    我有两个输入文件 每行都有名单 mm dd 形式 使用持续时间和其他主机名内容 另一个是我生成的 每行都有一组不重复的名单 我正在尝试编写一个 shell 命令来遍历带有名单的文件 将它们存储为变量并检查其他文件以匹配名称 然后输出每个人的
  • xna 中 spritebatch.draw 中的源矩形是什么

    SpriteBatch Draw 方法中源矩形参数的用途是什么 MSDN 说 A rectangle that specifies in texels the source texels from a texture Use null to
  • 使用 Adob​​e AIR 开发 Android 移动应用程序

    谁能提供使用 Eclipse SDK 和 Adob e AIR 开发 Android 移动应用程序之间的比较信息 请任何已经有使用 Adob e AIR 开发 Android 移动应用程序经验的人分享您的意见 我已经阅读了有关开发 Adob
  • 可以请求从 htmlhelper 访问查询字符串

    你好 可以在 HTMLHelper 扩展方法中访问查询字符串 我们需要根据请求中的查询字符串进行不同的渲染 是的 通过当前上下文 这是 HTML Helper 上的一个属性 public static string DoThis this
  • Three.JS Orbit Controls - 启用和禁用,无需位置跳跃

    我正在使用 Three JS 创建一个几何操作原型 我正在使用 OrbitControls JS 来操作相机 但在启用和禁用控件时遇到问题 这是我的演示 http moczys com webGL Prototype V02 05 html
  • 标头位置无法正常工作

    我的网址是 1006 我这里有一个没有任何操作的表格
  • 如何使 is_pod 测试在编译期间执行而不是执行期间执行?

    这可能是一个简单的问题 我根本不掌握 C 11 模板 我有一个通用向量类 但不是std vector
  • jQuery - 轮询作业队列

    我有一个包含作业队列的数据库表 一个单独的程序处理这些作业 我想提供一个网页供用户观看队列的进度 用于查询表并以 JSON 格式返回的服务器端脚本没有问题 我读过一些关于 jQuery 和期刊更新插件 http enfranchisedmi
  • 为什么片段类可能无效?

    我刚刚使用 AndroidStudio 向导创建了一个 PreferenceActivity 运行它引发了一个奇怪的异常 java lang RuntimeException Subclasses of PreferenceActivity
  • 使用下面的 uiimagePickerController Delegate 函数时获得不明确的引用:

    我试图覆盖 UIImagePickerControllerDelegate 中的 uiimagePickerController 函数 但是 我似乎收到错误 Ambiguous reference to member subscript 我
  • Android简单的警报对话框[重复]

    这个问题在这里已经有答案了 我需要向点击我的 Android 应用程序上的按钮的用户显示一条小短信 在 IOS 上我只需要创建一个 AlertView 它使用起来很简单 但在 Android 上我很困难 因为解决方案似乎困难十倍 我看到我需
  • IIS7:如何定义Windows身份验证已打开?

    IIS7 如何定义Windows身份验证已打开 我知道IIS7 集成模式不支持两阶段身份验证 https stackoverflow com questions 436169 iis7 setup integrated windows au
  • 从bind返回的结果和使用function()的结果有什么区别

    bind 的返回值与通过 function 创建等效值的结果有什么区别 有什么有效的区别吗 我不是在问上下文保留属性bind 是否有任何技术 性能原因导致您可能更喜欢一种方法 i e var myFunc foo bind undefine
  • 感应悬停在 JPanel 中 Path2D 圆的外边缘上[重复]

    这个问题在这里已经有答案了 因此 我有一个程序可以将 Path2D 圆绘制到 JPanel 上 我想要做的是当用户单击并拖动圆圈的右下角时调整圆圈的大小 所以 我想要的是检测它们何时在圆的右下角外边缘 而不是圆周围边界的右下角 基本上 我需
  • 使用 Zend Framework 的 Android RESTful Web 应用程序

    我编写了一个基于 Zend Framework 版本 1 11 11 的 Web 应用程序 我想使用相同的后端代码来编码该应用程序的移动版本 Android 为了实现这个目标 我想要获取 XML 和 JSON 格式的控制器中每个操作的响应