Tuesday, February 25, 2014

zend2 framework develop log 1– mysql and mvc and view helper and json response

Introduction:

This blog is about zend 2 framework,and not good. because is have so hard to read.

Contain:

  • mysql profile.
  • mvc
  • no view render
  • json output
  • gzip compress
  • view helper

 

1.db profile (mysql)

1.1 db profile

1.1.1 config/autoload/local.php

(description:this is local private profile file.)

<?php
/**
* Local Configuration Override
*
* This configuration override file is for overriding environment-specific and
* security-sensitive configuration information. Copy this file without the
* .dist extension at the end and populate values as needed.
*
* @NOTE: This file is ignored from Git by default with the .gitignore included
* in ZendSkeletonApplication. This is a good practice, as it prevents sensitive
* credentials from accidentally being committed into version control.
*/

define('PK_DEBUG_MODE',true);

return array(
// Whether or not to enable a configuration cache.
// If enabled, the merged configuration will be cached and used in
// subsequent requests.
//'config_cache_enabled' => false,
// The key used to create the configuration cache file name.
//'config_cache_key' => 'module_config_cache',
// The path in which to cache merged configuration.
//'cache_dir' => './data/cache',
// ...
'db' => array(
'driver' => 'Pdo',
'username' => 'root',
'password' => '',
'dsn' => 'mysql:dbname=db1;host=localhost',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
),
'service_manager' => array(
'factories' => array(
'Zend\Db\Adapter\Adapter' => function ($serviceManager) {
$adapterFactory = new Zend\Db\Adapter\AdapterServiceFactory();
$adapter = $adapterFactory->createService($serviceManager);

\Zend\Db\TableGateway\Feature\GlobalAdapterFeature::setStaticAdapter($adapter);

return $adapter;
}
),
),
);



1.1.2 config/autoload/global.php


(description:this is global profile file.)

<?php
/**
* Global Configuration Override
*
* You can use this file for overriding configuration values from modules, etc.
* You would place values in here that are agnostic to the environment and not
* sensitive to security.
*
* @NOTE: In practice, this file will typically be INCLUDED in your source
* control, so do not include passwords or other sensitive information in this
* file.
*/

return array(
// ...
'service_manager' => array(
'factories' => array(
'Zend\Db\Adapter\Adapter'
=> 'Zend\Db\Adapter\AdapterServiceFactory',
),
),
);



1.2 model


data table is “Keyword”:

CREATE TABLE `pkrss_rsskeyword` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`key` varchar(32) NOT NULL,
`count` int(11) NOT NULL,
`type` char(4) NOT NULL DEFAULT 'r' COMMENT 'r:rss b:bookimage',
PRIMARY KEY (`id`),
UNIQUE KEY `key` (`key`,`type`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8




and i used in module name “api”.


1.3 Module/Api/src/Api/Model/Keyword.php


(description:this is model data class.)

<?php
namespace Api\Model;

class Keyword
{
public $id;
public $key;
public $count;
public $type;

public function exchangeArray($data)
{
$this->id = (isset($data['id'])) ? $data['id'] : null;
$this->key = (isset($data['key'])) ? $data['key'] : null;
$this->count = (isset($data['count'])) ? $data['count'] : null;
$this->type = (isset($data['type'])) ? $data['type'] : null;
}

public function toArray(){
$ret = array();
$ret['id'] = $this->id;
$ret['key'] = $this->key;
$ret['count'] = $this->count;
$ret['type'] = $this->type;
return $ret;
}
}



1.4 Module/Api/src/Api/Model/KeywordTable.php


(description:this is model data table operator class.)


(i only test getkeywords function.)

<?php
namespace Api\Model;

use Zend\Db\TableGateway\TableGateway;
// use Zend\Console\Prompt\Select;
use Zend\Db\Sql\Select;

class KeywordTable
{
protected $tableGateway;

public function __construct(TableGateway $tableGateway)
{
$this->tableGateway = $tableGateway;
}

public function fetchAll()
{
$resultSet = $this->tableGateway->select();
return $resultSet;
}

public function getKeywords($type,$start=0,$limit=1)
{
$start = (int)$start;
$limit = (int)$limit;

$rowset = $this->tableGateway->select(function(Select $selector) use ($start,$limit,$type){
$selector->offset($start)
->limit($limit)
->order('count DESC')
->where(array('type' => $type));
});

$ret = array();
foreach ($rowset as $row) {
$ret []= $row->toArray();
}

return $ret;
}

public function getKeyword($id)
{
$id = (int)$id;

if(!$this->tableGateway->isInitialized())
$this->tableGateway->initialize();

$rowset = $this->tableGateway->select(array('id' => $id));
$ret = $rowset->current();
if($$ret)
$ret = $ret->toArray();

return $ret;
}

public function saveKeyword(Keyword $keyword)
{
$data = array(
'id' => $keyword->id,
'key' => $keyword->key,
'count' => $keyword->count,
'type' => $keyword->type,
);

$id = (int)$keyword->id;
if ($id == 0) {
$this->tableGateway->insert($data);
} else {
if ($this->getKeyword($id)) {
$this->tableGateway->update($data, array('id' => $id));
} else {
throw new \Exception('Keyword id does not exist');
}
}
}

public function deleteKeyword($id)
{
$this->tableGateway->delete(array('id' => $id));
}
}



1.5 Module/Api/src/Api/Controller/SearchController.php


(description:this is one sub controller,it call model and output with gzip compress json and no view render.)

<?php
namespace Api\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;

/**
* SearchController
* @see http://framework.zend.com/manual/2.0/en/user-guide/database-and-models.html
* @author liandeliang@gmail.com
*
* @version 1.0.0
*
*/
class SearchController extends AbstractActionController
{
protected $keywordTable;

public function getKeywordTable()
{
if (!$this->keywordTable) {
$sm = $this->getServiceLocator();
$this->keywordTable = $sm->get('Api\Model\KeywordTable');
}
return $this->keywordTable;
}

/**
* The default action - show the home page
*/
public function indexAction()
{
// TODO Auto-generated SearchController::indexAction() default action
return new ViewModel();
}

//public function nolayoutAction()
//{
// $view = new ViewModel();
// $view->setTerminal(true);
// return $view;
// }

/**
* example: http://localhost/book/public/api/search/list
*/
public function listAction(){

// get request param
$type = $this->params('type','b');
$start = (int)$this->params('start','0');
$limit = (int)$this->params('limit','20');

$table = $this->getKeywordTable();
$result = $table->getKeywords($type,$start,$limit);

\Application\View\Helper\OutputHelper::outputArray($result);

// output json,and exit,then can no render view.
exit();

return false;
}
}



2. mvc


2.1 screen shots:


image


2.1 module


module/Api/Module.php:


(description:this is module profile.)

<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/Api for the canonical source repository
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/

namespace Api;

// Add these import statements:
use Api\Model\Keyword;
use Api\Model\KeywordTable;
use Zend\Db\ResultSet\ResultSet;
use Zend\Db\TableGateway\TableGateway;

use Zend\ModuleManager\Feature\AutoloaderProviderInterface;
use Zend\Mvc\ModuleRouteListener;
use Zend\Mvc\MvcEvent;

class Module implements AutoloaderProviderInterface
{
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\ClassMapAutoloader' => array(
__DIR__ . '/autoload_classmap.php',
),
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
// if we're in a namespace deeper than one level we need to fix the \ in the path
__NAMESPACE__ => __DIR__ . '/src/' . str_replace('\\', '/' , __NAMESPACE__),
),
),
);
}

public function getConfig()
{
return include __DIR__ . '
/config/module.config.php';
}

public function onBootstrap(MvcEvent $e)
{
// You may not need to do this if you'
re doing it elsewhere in your
// application
$eventManager = $e->getApplication()->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach($eventManager);
}

// Add this method:
public function getServiceConfig()
{
return array(
'factories' => array(
'Api\Model\KeywordTable' => function($sm) {
$tableGateway = $sm->get('KeywordTableGateway');
$table = new KeywordTable($tableGateway);
return $table;
},
'KeywordTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Keyword());
return new TableGateway('pkrss_rsskeyword', $dbAdapter, null, $resultSetPrototype);
},
),
);
}
}




2.2 module config:


module/Api/config/module.config.php:


(description:this is module router profile.)

<?php
return array(
'controllers' => array(
'invokables' => array(
'Api\Controller\Search' => 'Api\Controller\SearchController',
),
),
'router' => array(
'routes' => array(
'api' => array(
'type' => 'Literal',
'options' => array(
// Change this to something specific to your module
'route' => '/api',
'defaults' => array(
// Change this value to reflect the namespace in which
// the controllers for your module are found
'__NAMESPACE__' => 'Api\Controller',
'controller' => 'search',
'action' => 'index',
),
),
'may_terminate' => true,
'child_routes' => array(
// This route is a sane default when developing a module;
// as you solidify the routes for your module, however,
// you may want to remove it and replace it with more
// specific routes.
'default' => array(
'type' => 'Segment',
'options' => array(
'route' => '/[:controller[/:action]]',
'constraints' => array(
'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
),
'defaults' => array(
),
),
),
),
),
),
),
'view_manager' => array(
'template_path_stack' => array(
'Api' => __DIR__ . '/../view',
),
),
);



2.3 view helper


module/Application/src/Application/View/Helper/OutputHelper.php:


(description:this is output with json and gzip detect.)

<?php
/**
* Application
*
* @author
* @version
*/
namespace Application\View\Helper;

use Zend\View\Helper\AbstractHelper;

class ArrayToXML
{
/**
* The main function for converting to an XML document.
* Pass in a multi dimensional array and this recrusively loops through and builds up an XML document.
*
* @param array $data
* @param string $rootNodeName - what you want the root node to be - defaultsto data.
* @param SimpleXMLElement $xml - should only be used recursively
* @return string XML
*/
public static function toXml($data, $xmlDoc, $xmlNode=null)
{
// loop through the data passed in.
foreach($data as $key => $value)
{
if (is_numeric($key))
{
// make string key...
$key = 'item';
}

// if there is another array found recrusively call this function
if (is_array($value))
{
$xmlNode2 = $xmlNode->appendChild($xmlDoc->createElement($key));

ArrayToXML::toXml($value, $xmlDoc, $xmlNode2);
}
else
{
$xmlTextNode = $xmlDoc->createTextNode($value);
$xmlUrlNode = $xmlDoc->createElement($key);
$xmlUrlNode->appendChild($xmlTextNode);
$xmlNode->appendChild($xmlUrlNode);
}
}
}
}

$log_file = null;
/**
* OutputHelper Action Helper
*
* @uses actionHelper Zend_Controller_Action_Helper
*/
/**
* View Helper
*/
class OutputHelper extends AbstractHelper
{

public function __invoke($in)
{
// TODO Auto-generated OutputHelper::__invoke
return $in;
}

public static function outputErrorMessage($code = -1,$msg = "Error"){
self::outputArray(array('code' => $code, 'message' => $msg));
exit();
}

public static function log($output){
global $log_file;
if(!$log_file)
$log_file = fopen('1.txt','w');
if($log_file)
fwrite($log_file,$output . "\r\n");
}

public static function outputArray($output,$type = 'json'){
$ret = self::getDataFromArray($output,$type);
return self::outputData($ret,$output);
}

public static function outputData($output,$type){
//header('Access-Control-Allow-Origin: *');

if ($type=='xml') {
header("Content-Type: text/xml");
} else if ($type=='js') {
header("Content-type: application/x-javascript");
} else if ($type=='txt') {
header("Content-type: text/plain");
} else {
header("Content-type: application/json");
}

return self::ob_echo($output);
}

public static function getDataFromArray($output,$type){

if ($type=='xml') {
$xmlDoc = new DOMDocument("1.0","utf-8");
$xmlNode = $xmlDoc->appendChild($xmlDoc->createElement("items"));

ArrayToXML::toXml($output, $xmlDoc, $xmlNode);

$xmlDoc->formatOutput = true;
return $xmlDoc->saveXml();
}else if ($type=='js') {
return @json_encode($output); // 'var result=' .
}else if ($type=='htm') {
return $output; // 'var result=' .
} else {
return @json_encode($output);
}
}

public static function is_gzip(){
if(defined('PKRSS_DEBUG') && PKRSS_DEBUG)
return false;
if(empty($_SERVER['HTTP_ACCEPT_ENCODING']))
return false;
return substr_count($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip');
}

public static function ob_echo($content){
if (self::is_gzip())
ob_start("ob_gzhandler");
else
ob_start();
echo $content;
ob_end_flush();

return $content;
}
}


class UtilsHelper {
public static function getPost($name){
if(defined('PKRSS_DEBUG') && PKRSS_DEBUG)
return self::getParam($name);
if(isset($_POST[$name]))
return $_POST[$name];
return null;
}

public static function getGet($name){
if(isset($_GET[$name]))
return $_GET[$name];
return null;
}

public static function getParam($name){
if(isset($_GET[$name]))
return $_GET[$name];
else if(isset($_POST[$name]))
return $_POST[$name];
return null;
}

public static function getReferHost(){
if(defined('PKRSS_DEBUG') && PKRSS_DEBUG){
return '';
}

if(!isset($_SERVER["HTTP_REFERER"]) || empty($_SERVER["HTTP_REFERER"]))
OutputHelper::outputErrorMessage(-1,'http header referer checked fail!');
$url = $_SERVER["HTTP_REFERER"];
return parse_url($url, PHP_URL_HOST);
}

public static function safe_require($file){
if(file_exists($file)){
require $file;
return true;
}
return false;
}

}

No comments: