zf2 - Nested Aggregate Hydrators - zend-framework2

Is it possible to nest aggregate hydrators? If i have the following classes:
class Appointment{
public date;
public startTime;
public endTime;
public User; //* #var User */
}
class User{
public Location; //* #var Location*/
}
...being populated with the following AggregateHydrator (created from a factory):
class AppointmentModelHydratorFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator) {
$serviceManager = $serviceLocator->getServiceLocator();
$arrayHydrator = new ArraySerializable();
$arrayHydrator->addStrategy('date', new DateTimeStrategy())
->addStrategy('endTime', new TimeStrategy())
->addStrategy('startTime', new TimeStrategy());
$aggregateHydrator = new AggregateHydrator();
$aggregateHydrator->add($arrayHydrator);
$aggregateHydrator->add($serviceLocator->get('Hydrator\User'));
return $aggregateHydrator;
}
}
With the UserHydratorFactory looking like:
class UserHydratorFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator) {
$sm = $serviceLocator->getServiceLocator();
$userHydrator = new UserHydrator($sm->get('User\Mapper'));
$aggregateHydrator = new AggregateHydrator();
$aggregateHydrator->add($userHydrator );
$aggregateHydrator->add($sm->get('HydratorManager')->get('Hydrator\User\Location'));
return $aggregateHydrator;
}
}
This is throwing an expection as the model is being returned as null, but if i comment out adding the Location hydrator to the User hydrator, it works fine (albeit without location data loaded). So i was wondering if aggregate hydrators are able to be nested?

It is not built-in, but doable.
namespace Hydrator;
use Zend\Stdlib\Hydrator\HydratorInterface;
class NestedHydrator implements HydratorInterface
{
protected $inner_hydrator;
private $empty;
public function __construct ($inner_hydrator, $empty)
{
$this->inner_hydrator = $inner_hydrator;
$this->empty = $empty;
}
public function extract ($object)
{
return [
$this->getPath() => $this->inner_hydrator->extract ($object->{$this->getPath()})
];
}
public function hydrate (array $data, $object)
{
$object->{$this->getPath()} = $this->inner_hydrator->hydrate ($data [$this->getPath()], $this->empty);
return $object;
}
protected function getPath ()
{
return get_class ($this->empty);
}
}
And then:
$u = new User();
$u->Location = "4 Clinton Rd.";
$a = new Appointment();
$a->date = "yesterday";
$a->startTime = "7:00";
$a->endTime = "8:00";
$a->User = $u;
$h = new AggregateHydrator();
$h->add (new ObjectProperty());
$nested = new \Hydrator\NestedHydrator(new ObjectProperty(), new User());
$h->add ($nested);
$data = $h->extract ($a);
$b = $h->hydrate ($data, new Appointment());
$this->assertEquals ($a, $b);

Related

get several values ​separated by , and save line by line in the database

I have an input, and I want to extract several numbers separated by , and store each number on each new line in the database.
model - CouponDocument
<?php
namespace App\Models;
use App\Http\Controllers\CouponDocumentController;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class CouponDocument extends Model
{
use HasFactory, SoftDeletes;
protected $table = "coupons_document";
protected $fillable = [
"id",
"cpf",
"coupon_id"
];
protected $hidden = [
'deleted_at',
'created_at',
'updated_at'
];
public function coupon()
{
return $this->belongsTo(Coupon::class, 'coupon_id', 'id')->withTrashed();
}
}
Controller
class CouponDocumentController extends Controller
{
static public function store($request)
{
$data = [];
foreach ($request->input('cpf') as $cpf) {
$data[] = [
'cpf' => trim($cpf),
'coupon_id' => 61
];
}
foreach ($data as $item) {
$couponDocument = new CouponDocument();
$couponDocument->fill($item);
$couponDocument->save();
}
}
}
Resources
class CouponsDocument extends Resource
{
use SearchesRelations;
public static $displayInNavigation = false;
public static $model = \App\Models\CouponDocument::class;
public static $title = 'id';
public static $search = [
'id',
'cpf',
'coupon_id'
];
public static function label()
{
return __('modules.couponDocument.button');
}
public static function singularLabel()
{
return __('modules.couponDocument.button');
}
public function fields(Request $request)
{
return [
Text::make(__('fields.couponDocument.name'), "cpf")
->sortable(),
];
}
where the resource is called
HasMany::make
__("fields.couponDocument.name"),
"documentRelationship",
CouponsDocument::class
I tried to do it with the standard functions of nova, but it ended up not working, I would like to know if there is any other solution

ZF FactoryInterface - using options parameter for configuring loading dependencies

I am wondering about the best practices for loading complex objects.
To begin with, i'm going to outline some boilerplate before getting to the problem.
Assume the following: A simple domain model Client is loaded using a tablegateway, with factories used at every stage to inject dependencies:
namespace My\Model\Client;
class Client implements InputFilterProviderInterface
{
/**#var integer*/
protected $id;
/**#var InputFilter*/
protected $inputFilter;
/**#var Preferences */
protected $preferences;
/**#var Orders*/
protected $orders;
/**#var Contacts*/
protected $contacts;
}
A factory for this Client object:
namespace My\Model\Client;
class ClientFactory implements FactoryInterface
{
public function($container, $requestedName, $options)
{
$client = new Client();
$client->setInputFilter($container->get('InputFilterManager')->get('ClientInputFilter'));
return $client;
}
}
Next the mapper factory, which uses a TableGateway:
namespace My\Model\Client\Mapper;
class ClientMapperFactory implements FactoryInterface
{
public function __invoke($container, $requestedName, $options)
{
return new ClientMapper($container->get(ClientTableGateway::class));
}
}
The TableGatewayFactory:
namespace My\Model\Client\TableGateway
class ClientTableGatewayFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$hydrator = new ArraySerialisable();
$rowObjectPrototype = $container->get(Client::class);
$resultSet = new HydratingResultSet($hydrator, $rowObjectPrototype);
$tableGateway = new TableGateway('clients', $container->get(Adapter::class), null, $resultSet);
return $tableGateway;
Note the use of a HydratingResultset to return fully formed Client objects from the ResultSet.
This all works nicely.
Now the Client object has several related objects as properties, so whilst using the HydratingResultSet, i'm going to add an AggregateHydrator to load them:
class ClientTableGatewayFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
**$hydrator = $container->get('HydratorManager')->get(ClientHydrator::class);**
$rowObjectPrototype = $container->get(Client::class);
$resultSet = new HydratingResultSet($hydrator, $rowObjectPrototype);
$tableGateway = new TableGateway('clients', $container->get(Adapter::class), null, $resultSet);
return $tableGateway;
}
Finally, the Clients hydrator factory:
class ClientHydratorFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
//base ArraySerializable for Client object hydration
$arrayHydrator = new ArraySerializable();
$arrayHydrator->addStrategy('dateRegistered', new DateTimeStrategy());
$aggregateHydrator = new AggregateHydrator();
$aggregateHydrator->add($arrayHydrator);
$aggregateHydrator->add($container->get('HydratorManager')->get(ClientsAddressHydrator::class));
$aggregateHydrator->add($container->get('HydratorManager')->get(ClientsOrdersHydrator::class));
$aggregateHydrator->add($container->get('HydratorManager')->get(ClientsPreferencesHydrator::class));
$aggregateHydrator->add($container->get('HydratorManager')->get(ClientsContactsHydrator::class));
return $aggregateHydrator;
}
}
... with the gist of the above hydrators being like:
class ClientsAddressHydrator implements HydratorInterface
{
/** #var AddressMapper */
protected $addressMapper;
public function __construct(AddressMapper $addressMapper){
$this->addressMapper = $addressMapper;
}
public function extract($object){return $object;}
public function hydrate(array $data, $object)
{
if(!$object instanceof Client){
return;
}
if(array_key_exists('id', $data)){
$address = $this->addressMapper->findClientAddress($data['id']);
if($address instanceof Address){
$object->setAddress($address);
}
}
return $object;
}
}
Finally we're at the issue. The above works perfectly and will load quite cleanly a Client object with all the related objects fully formed. But i have some resources where the entire object graph is not needed - for instance, when viewing a table of all clients - there is no need for any more information to be loaded.
So i've been thinking of ways of using the factories to choose which dependencies to include.
Solution 1
A factory for each use case. If only the Client data is needed (with no dependencies), then create a series of factories ie ClientFactory, SimpleClientFactory, ComplexClientFactory, ClientWithAppointmentsFactory etc. Seems redundant and not very reusable.
Solution 2
Use the options param defined in the FactoryInterface to pass "loading" options to the hydrator factory, eg:
class ViewClientDetailsControllerFactory implements FactoryInterface
{
//all Client info needed - full object graph
public function __invoke($container, $requestedName, $options)
{
$controller = new ViewClientDetailsController();
$loadDependencies = [
'loadPreferences' => true,
'loadOrders' => true,
'loadContacts' => true
];
$clientMapper = $container->get(ClientMapper::class, '', $loadDependencies);
return $controller;
}
}
class ViewAllClientsControllerFactory implements FactoryInterface
{
//Only need Client data - no related objects
public function __invoke($container, $requestedName, $options)
{
$controller = new ViewAllClientsController();
$loadDependencies = [
'loadPreferences' => false,
'loadOrders' => false,
'loadContacts' => false
];
$clientMapper = $container->get(ClientMapper::class, '', $loadDependencies);
return $controller;
}
}
The mapper factory passes the options to the tablegateway factory, that passes them on to the hydrator factory:
class ClientTableGatewayFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$hydrator = $container->get('HydratorManager')->get(ClientHydrator::class, '', $options);
$rowObjectPrototype = $container->get(Client::class);
$resultSet = new HydratingResultSet($hydrator, $rowObjectPrototype);
$tableGateway = new TableGateway('clients', $container->get(Adapter::class), null, $resultSet);
return $tableGateway;
}
Finally, we can define here how much info to load into the Client:
class ClientHydratorFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
//base ArraySerializable for Client object hydration
$arrayHydrator = new ArraySerializable();
$arrayHydrator->addStrategy('dateRegistered', new DateTimeStrategy());
$aggregateHydrator = new AggregateHydrator();
$aggregateHydrator->add($arrayHydrator);
if($options['loadAddress'] === true){
$aggregateHydrator->add($container->get('HydratorManager')->get(ClientsAddressHydrator::class));
}
if($options['loadOrders'] === true){
$aggregateHydrator->add($container->get('HydratorManager')->get(ClientsOrdersHydrator::class));
}
if($options['loadPreferences'] === true){
$aggregateHydrator->add($container->get('HydratorManager')->get(ClientsPreferencesHydrator::class));
}
if($options['loadContacts'] === true){
$aggregateHydrator->add($container->get('HydratorManager')->get(ClientsContactsHydrator::class));
}
return $aggregateHydrator;
}
}
This seems to be a clean solution, as the dependencies can be defined per request. However i don't think that this is using the options param as intended - the documentation states that this parameter is supposed to be for passing constructor params to the object, not defining what logic the factory should use to load dependencies.
Any advice, or alternative solutions to achieve the above, would be great. Thanks for reading.
Creating a big palette of all possible combinations would not be just a nightmare, but a declared suicide.
Using options
I wouldn't suggest you this option either. I mean, it's not that bad, but it has a major issue: everytime you instantiate your hydrator, you should remember to pass those options, or you'll get an "empty hydrator". Same logic applies to everything that uses those hydrators.
Since you actually want to remove hydrators you don't need, I'd suggest to avoid this solution, because this way you are always forced to declare which hydrators you need (and, honestly, I'll always forget to do it.. ^^ ).
If you add a new hydrator, you'll have to go through your project and add new options. Not really worth the effort...
That's why I propose you the next solution
Removing unnecessary hydrators
In 99% of the cases, hydrators are used by mappers. Thus, I think it would be cleanier to have a mapper which, by default, returns always the same kind of data (->a single hydrator), but that it can be modified to remove a certain set of hydrators.
Inside the AggregateHydrator, all hydrators are converted into listeners and attached to EventManager. I had some issue while trying to get all events, so I turned on creating an aggregate hydrator with the option to detach an hydrator:
class DetachableAggregateHydrator extends AggregateHydrator
{
/**
* List of all hydrators (as listeners)
*
* #var array
*/
private $listeners = [];
/**
* {#inherit}
*/
public function add(HydratorInterface $hydrator, int $priority = self::DEFAULT_PRIORITY): void
{
$listener = new HydratorListener($hydrator);
$listener->attach($this->getEventManager(), $priority);
$this->listeners[get_class($hydrator)] = $listener;
}
/**
* Remove a single hydrator and detach its listener
*
* #param string $hydratorClass
*/
public function detach($hydratorClass)
{
$listener = $this->listeners[$hydratorClass];
$listener->detach($this->getEventManager());
unset($listener);
unset($this->listeners[$hydratorClass]);
}
}
Then, in the TableGatewayFactory:
class ClientTableGatewayFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$hydrator = $container->get('HydratorManager')->get(ClientHydrator::class);
$rowObjectPrototype = $container->get(Client::class);
$resultSet = new HydratingResultSet($hydrator, $rowObjectPrototype);
$adapter = $container->get(Adapter::class);
$tableGateway = new TableGateway('clients', $adapter, null, $resultSet);
return $tableGateway;
}
}
And the ClientHydratorFactory:
class ClientHydratorFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$aggregateHydrator = new DetachableAggregateHydrator();
$arrayHydrator = new ArraySerializable();
$arrayHydrator->addStrategy('dateRegistered', new DateTimeStrategy());
$aggregateHydrator->add($arrayHydrator);
$hydratorManager = $container->get('HydratorManager');
$aggregateHydrator->add($hydratorManager->get(ClientsAddressHydrator::class));
$aggregateHydrator->add($hydratorManager->get(ClientsOrdersHydrator::class));
$aggregateHydrator->add($hydratorManager->get(ClientsPreferencesHydrator::class));
$aggregateHydrator->add($hydratorManager->get(ClientsContactsHydrator::class));
return $aggregateHydrator;
}
}
You just need to make tablegateway accessible by outstide the mapper:
class ClientMapper
{
private $tableGateway;
// ..
// Other methods
// ..
public function getTableGateway(): TableGateway
{
return $this->tableGateway;
}
}
And now you're able to choose which hydrators you don't want to attach.
Let's say you have two controllers:
ClientInfoController, where you need clients and their address, preferences and contacts
ClientOrdersController, where you need clients with their orders
Their factories will be:
class ClientInfoController implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$clientMapper = $container->get(ClientMapper::class);
// Orders are unnecessary
$resultSetPrototype = $clientMapper->getTableGateway()->getResultSetPrototype();
$resultSetPrototype->getHydrator()->detach(ClientsOrdersHydrator::class);
return $aggregateHydrator;
}
}
class ClientOrdersController implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$clientMapper = $container->get(ClientMapper::class);
// Orders are unnecessary
$resultSetPrototype = $clientMapper->getTableGateway()->getResultSetPrototype();
$resultSetPrototype->getHydrator()->detach(ClientsAddressHydrator::class);
$resultSetPrototype->getHydrator()->detach(ClientsPreferencesHydrator::class);
$resultSetPrototype->getHydrator()->detach(ClientsContactsHydrator::class);
return $aggregateHydrator;
}
}

Zend Framework 2: How can I use my Abtract model for extending a model?

I have a project with structure: https://docs.google.com/file/d/0B6hBvUW6YcomNHZJYUxvbTgxNkE
This is my AbstractTable.php:
namespace AdminManage\Model;
use Zend\Db\Adapter\Adapter;
use Zend\ServiceManager\ServiceLocatorInterface;
class AbstractTable{
protected $tablegateway;
protected $table;
protected $serviceLocator;
protected $adapter;
public function __construct(TableGateway $tableGateway) {
$this->tableGateway = $tableGateway;
$this->table = $this->tableGateway->getTable();
}
public function setServiceLocator(ServiceLocatorInterface $serviceLocator){
$this->serviceLocator = $serviceLocator;
return $this;
}
public function getServiceLocator(){
return $this->serviceLocator;
}
public function setDbAdapter(Adapter $adapter){
$this->adapter = $adapter;
return $this;
}
public function getDbAdapter(){
return $this->adapter;
}
public function fetchAll(){
return $this->tablegateway->select();
}
public function getTable(){
if(!$this->table)
$this->table = $this->tableGateway->getTable();
return $this->table;
}
}
This is my CategoryTable.php:
namespace Category\Model;
use Zend\Db\Sql\Sql;
use AdminManage\Model\AbstractTable;
class CategoryTable extends AbstractTable {
public function getListCategory() {
$adapter = $this->getDbAdapter ();
$sql = new Sql ( $adapter );
$select = $sql->select ( array (
"c" => "category"
) )->join ( array (
"cd" => "category_description"
), "c.category_id = cd.category_id" );
echo $sql->prepareStatementForSqlObject ( $select )->getSql ();
}
}
When I call getListCategory() in the controller, has an error:
Fatal error: Class 'AdminManage\Model\AbstractTable' not found in D:\xampp\htdocs\dokusyu\htdocs\admin\dokusyu_be\module\Course\src\Category\Model\CategoryTable.php on line 5.
How can I fix this error? Thank you!
ZF2 refer all files from root folder of your host, try creating a subdomain and and copy the files and access the pages

Custom authentication via SOAP webservice using ZF2

I am trying to implement Custom authentication via SOAP webservice
as per Refering links
http://it-cook-de.blogspot.in/2013/07/zend-framework-2-custom-authentication-with-soap-webservice-part-1.html
http://samsonasik.wordpress.com/2012/10/23/zend-framework-2-create-login-authentication-using-authenticationservice-with-rememberme/#comment-6117
Now getting error as
Code :
<?php
namespace Application\Adapter;
use Zend\Authentication\Adapter\AdapterInterface;
use Zend\Authentication\Result;
use Zend\Soap\Client;
use Zend\Soap\Client\DotNet as DotNet;
class SoapAuthenticationAdapter implements AdapterInterface
{
//:TODO: move to configuration
//private $module = 'my_application_name_in_auth_system';
private $module = 'student';
//:TODO: move to configuration
// private $uri = 'full_url_to_soap_webservice_of_auth_system';
private $uri = 'http://ip/Service/student.svc?wsdl';
//:TODO: move to configuration
//private $location = 'full_url_to_soap_webservice_of_auth_system';
private $location = 'http://ip/Service/student.svc?wsdl';
protected $username;
protected $password;
protected $customercode;
function __construct()
{
}
public function authenticate()
{
$client = new DotNet($this->uri);
$param=array("customercode"=>$this->customercode,"username"=>$this->username,"password"=>$this->password);
$result = $client->call('ValidateUser',array($param));
if ($result) {
$this->permissions = $param;
return $this->getResult(Result::SUCCESS, $this->permissions, 'SUCCESS');
} else {
return $this->getResult(Result::FAILURE_CREDENTIAL_INVALID, null, 'FAILURE_CREDENTIAL_INVALID');
}
} catch (\SoapFault $e) {
// switch ($e->getMessage()) {
return $this->getResult(Result::FAILURE_UNCATEGORIZED, null, $e->getMessage());
// }
}
}
public function setIdentity($username)
{
$this->username = $username;
}
public function setCredential($password)
{
$this->password = $password;
}
public function setCustomerCode($customercode)
{
$this->customercode =$customercode;
}
private function getResult($type, $identity, $message)
{
return new Result($type, $identity, array(
$message
));
}
}
/////In IndexController
public function getAuthService()
{
if (! $this->authservice) {
$this->authservice = $this->getServiceLocator()
->get('SoapAuthenticationService');
}
return $this->authservice;
}
public function someAction()
{
$request = $this->getRequest();
if ($request->isPost()){
$this->getAuthService()->getAdapter()
->setIdentity($request->getPost('username'))
->setCredential($request->getPost('password'))
->setCustomerCode($request->getPost('customercode'));
$result = $this->getAuthService()->authenticate();
foreach($result->getMessages() as $message)
{
//save message temporary into flashmessenger
$this->flashmessenger()->addMessage($message);
}
if ($result->isValid()) {
$redirect = 'home';
//check if it has rememberMe :
if ($request->getPost('rememberme') == 1 ) {
$this->getSessionStorage()
->setRememberMe(1);
//set storage again
$this->getAuthService()->setStorage($this->getSessionStorage());
}
$this->getAuthService()->setStorage($this->getSessionStorage());
$this->getAuthService()->getStorage()->write($request->getPost('username'));
}
else
{
$redirect ='login';
}
return $this->redirect()->toRoute($redirect);
}
in module.php
public function getServiceConfig()
{
return array(
'factories' => array(
//Add the following lines
'Application\Model\SoapAuthenticationStorage' => function($sm){
return new SoapAuthenticationStorage('student');
},
'SoapAuthenticationService' => function($sm) {
$authAdapter = new SoapAuthenticationAdapter();
$authService = new AuthenticationService();
$authService->setAdapter($authAdapter);
$authService->setStorage($sm->get('Application\Model\SoapAuthenticationStorage'));
return $authService;
}
)
);
}
Any help to solve this
Each of the set methods in your adapter need to return $this in order to allow you to chain method calls together (this is called a 'fluent interface'). E.g.:
public function setIdentity($username)
{
$this->username = $username;
return $this;
}
That should fix the error you're getting.

ZendFramework2 AbstractTableGateway getSql

I got a ZF2 project with 2 Models PosTable/TopTable which extend AbstractTableGateway.
I want to Paginate results from those Tables so i have a Pagination function in both of them.
this is what the PosTable Model looks like:
...
class PosTable extends AbstractTableGateway {
public function __construct($adapter) {
$this->table = 'pos';
$this->adapter = $adapter;
}
...
public function getPosPaginator($tid) {
$sql = $this->getSql();
$select = $sql->select();
$select->where('tid = '.$tid)->where('deleted = 0')->order('crdate ASC');
$adapter = new \Zend\Paginator\Adapter\DbSelect($select, $sql);
$paginator = new \Zend\Paginator\Paginator($adapter);
return $paginator;
}
...
which works perfectly.
but in my TopTable it looks the same like this:
...
class TopTable extends AbstractTableGateway {
public function __construct($adapter) {
$this->table = 'top';
$this->adapter = $adapter;
}
public function getTopPaginator($fid) {
$sql = $this->getSql();
$select = $sql->select();
$select->where('fid = '.$fid)->where('deleted = 0');
$adapter = new \Zend\Paginator\Adapter\DbSelect($select, $sql);
$paginator = new \Zend\Paginator\Paginator($adapter);
return $paginator;
}
...
my controller looks like this for PosTable:
...
public function posAction(){
...
$pos = $this->getPosTable()->getPosPaginator($tid);
$pos->setCurrentPageNumber($pageid)->setItemCountPerPage(19);
... return $pos etc...
same controller topAction:
...
public function topAction(){
...
$top = $this->getTopTable()->getTopPaginator($fid);
$top->setCurrentPageNumber($pageid)->setItemCountPerPage(20);
...return $top etc..
in that controller i got also these functions:
public function getTopTable(){
return $this->getServiceLocator()->get('Application\Model\TopTable');
}
public function getPosTable(){
return $this->getServiceLocator()->get('Application\Model\PosTable');
}
PosTable Pagination works perfectly, but the TopTable Pagination doesnt work.
i get this error:
Fatal error: Call to a member function select() on a non-object in ....
seems like
$sql = $this->getSql();
doesnt return the object.
how can i solve this problem?
one works one doesnt for no obvious reason.
my module.php looks like this:
namespace Application;
class Module
{
public function getAutoloaderConfig()
{
return array('Zend\Loader\StandardAutoloader' =>
array('namespaces' =>
array(__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,),
),
);
}
public function getConfig()
{
return include __DIR__ . '/config/module.config.php';
}
public function getServiceConfig()
{
return array(
'factories' => array(
'Application\Model\TopTable' => function($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$table = new \Application\Model\TopTable($dbAdapter);
return $table;
},
'Application\Model\ForTable' => function($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$table = new \Application\Model\ForTable($dbAdapter);
return $table;
},
'Application\Model\PosTable' => function($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$table = new \Application\Model\PosTable($dbAdapter);
return $table;
},
),
);
}
}
Ok, after going through TableGateway Code and your extended class, I found the your implementation is not calling initialize which setup the sql object try to call the parent table gateway, below is the modified constructor for your PosTable and TopTable
/* for PosTable */
class PosTable extends TableGateway {
public function __construct($adapter) {
parent::__construct('pos', $adapter);
}
...
/* for TopTable */
class TopTable extends TableGateway {
public function __construct($adapter) {
parent::__construct('top', $adapter);
}
...

Resources