ZF2 Accessing routes and posts via a factory - zend-framework2

I am trying to access a route and post via a form factory. The route or the post contains an ID which I need to inject into my form so that I can build a select statement.
Currently I am injecting into the form via the controller using
$this->MyForm->get('elementName')->setOptions(array('value_options' =>$myArrayOfOptions));
My goal is to keep the business logic out of the controller hence why I am keen to use the formFactory instead however I do need access to the ID in the post or route to achieve this.
My Form Factory looks like this:
<?php
namespace MyModule\Form;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use AdminLottery\InputFilter\MyFilter;
use AdminLottery\Service\MyService;
class MyFormFactory implements FactoryInterface
{
/**
* Create service
*
* #param ServiceLocatorInterface $serviceLocator
* #return mixed
*/
public function createService(
ServiceLocatorInterface $serviceLocator
)
{
//$serviceLocator is FormElementManager
$realSL = $serviceLocator->getServiceLocator();
//*** I NEED TO ACCESS THE ID / POST HERE TO SEND TO MY FORM
return new MyForm(
$realSL->get('Doctrine\ORM\EntityManager'),
$realSL->get('InputFilterManager')->get(MyFilter::class),
$realSL,
$realSL->get(MyService::class)
);
}
}
Any Ideas??

You can access the request instance
MyFormFactory
//...
$request = $serviceLocator->getServiceLocator()->get('Request');
$id = $request->getPost('id', false);
if ($id) $form->setOption('id', $id);
//...
Edit: This is very similar to another question I answered
Edit 2
In your factory can access the route params via the router's Zend\Mvc\Router\RouteMatch.
$request = $serviceLocator->getServiceLocator()->get('Request');
$router = $serviceLocator->getServiceLocator()->get('Router');
$match = $router->match($request); // \Zend\Mvc\Router\RouteMatch
$id = ($match) ? $match->getParam('id', false) : false;
if ($id) $form->setOption('id', $id); //....

For anyone looking for a reference, I thought I would add the final code I used:
Semi-final code::
$router = $realSL->get('Router');
$request = $realSL->get('Request');
$routeMatch = $router->match($request);
$matchArray = $routeMatch->getParams();
if (isset($matchArray['id'])) {
$id = (int) $matchArray['id'];
} else {
$id = 0;
}
Final code::
$realSL->get('application')->getMvcEvent()->getRouteMatch()->getParam('id', 0)

Here is an example for a controller factory, that would work in the same manner for any other factory:
namespace MyModule\Controller\Factory;
use MyModule\Controller\MyController;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class MyControllerFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
/*
* #var Zend\ServiceManager\ServiceManager
*/
$realServiceLocator = $serviceLocator->getServiceLocator();
...
$router = $realServiceLocator->get('router');
$request = $realServiceLocator->get('request');
$routerMatch = $router->match($request);
...
$test1 = $routerMatch->getParams();
$test2 = $request->getQuery();
$test3 = $request->getPost();
...
return new MyController(...);
}
}

Related

TYPO3 xClass and Dependency Injection

I want to override an Extbase Controller, e.g. news in TYPO3 v10.4. Therefore I register an XClass in my ext_locaconf.php
$GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][\GeorgRinger\News\Controller\NewsController::class] = [
'className' => \Clickstorm\CsEvents\Controller\EventController::class
];
Afterwards I want to inject my new Repository
/**
* eventDateRepository
*
* #var EventDateRepository
*/
protected $eventDateRepository = null;
/**
* Inject a eventDateRepository
*
* #param EventDateRepository $eventDateRepository
*/
public function injectEventDateRepository(EventDateRepository $eventDateRepository)
{
$this->eventDateRepository = $eventDateRepository;
}
But my eventDateRepository is null. Also when I use a constructor instead.
Even though I don't know the reason for such a behaviour, a sustainable workaround is to manually instantiate your dependencies in the initializeAction method.
In my case, this is what I wrote:
/**
* #var \TYPO3\CMS\Extbase\Service\ImageService
*/
protected $imageService;
public function initializeAction()
{
parent::initializeAction();
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
$this->imageService = $objectManager->get(\TYPO3\CMS\Extbase\Service\ImageService::class);
}

Laravel Nova - How to determine the view (index, detail, form) you are in for a resource's computed field?

I would like to return a different result for a computed field when viewing the index view than when viewing the detail view of a resource.
Basically something like viewIs() below:
Text::make('Preview', function () {
if($this->viewIs('index'){
return \small_preview($this->image);
}
return \large_preview($this->image);
})->asHtml(),
You can check the class of the request:
Text::make('Preview', function () use ($request) {
if ($request instanceof \Laravel\Nova\Http\Requests\ResourceDetailRequest) {
return \large_preview($this->image);
}
return \small_preview($this->image);
});
Otherwise, you can create your own viewIs function:
// app/Nova/Resource.php
/**
* Check the current view.
*
* #param string $view
* #param \Laravel\Nova\Http\Requests\NovaRequest $request
* #retrun bool
*/
public function viewIs($view, $request)
{
$class = '\Laravel\Nova\Http\Requests\\Resource'.ucfirst($view).'Request';
return $request instanceof $class;
}
Then you can do it like this:
Text::make('Preview', function () use ($request) {
if ($this->viewIs('detail', $request) {
return \large_preview($this->image);
}
return \small_preview($this->image);
});
Unfortunately, #Chin's answer did not work for me as for Edit view the request class is just a basic Laravel\Nova\Http\Request class.
My workaround to check if this is an index view is as follows:
/**
* Check if the current view is an index view.
*
* #param \Laravel\Nova\Http\Requests\NovaRequest $request
* #return bool
*/
public function isIndex($request)
{
return $request->resourceId === null;
}
The NovaRequest class will soon be able to help, as the isResourceIndexRequest and isResourceDetailRequest are already in master.
As the Nova repo is private I will keep you posted, when it will be usable.
In the meantime I am falling back to helper methods on the Nova Resource class (app/Nova/Resource.php):
namespace App\Nova;
use Laravel\Nova\Http\Requests\ResourceDetailRequest;
use Laravel\Nova\Http\Requests\ResourceIndexRequest;
use Laravel\Nova\Resource as NovaResource;
use Laravel\Nova\Http\Requests\NovaRequest;
abstract class Resource extends NovaResource
{
// [...]
/**
* Determine if this request is a resource index request.
*
* #return bool
*/
public function isResourceIndexRequest($request)
{
return $request instanceof ResourceIndexRequest;
}
/**
* Determine if this request is a resource detail request.
*
* #return bool
*/
public function isResourceDetailRequest($request)
{
return $request instanceof ResourceDetailRequest;
}
}
Usage:
public function fields(Request $request)
{
$fields = [
// [...]
];
if ($this->isResourceDetailRequest($request)) {
if ($this->isResourceDetailRequest($request)) {
$fields = array_merge($fields, [
// [...]
]);
}
}
return $fields;
}
I added this little helper class
namespace App\Helpers;
class CurrentResourceAction {
public static function isIndex($request)
{
return $request instanceof \Laravel\Nova\Http\Requests\ResourceIndexRequest;
}
public static function isDetail($request)
{
return $request instanceof \Laravel\Nova\Http\Requests\ResourceDetailRequest;
}
public static function isCreate($request)
{
return $request instanceof \Laravel\Nova\Http\Requests\NovaRequest &&
$request->editMode === 'create';
}
public static function isUpdate($request)
{
return $request instanceof \Laravel\Nova\Http\Requests\NovaRequest &&
$request->editMode === 'update';
}
}
you can call it anywhere you need to
A bit late but hey! You can check against the NovaRequest properties editing and editMode ('create', 'update', 'attach' etc.)
// Determine if you are creating a model.
$request->editMode == 'create';
Or as they say, "Read the source Luke" and see how they determine it. See the Laravel\Nova\Http\Requests\NovaRequest, it contains similar checks.
namespace Laravel\Nova\Http\Requests;
class NovaRequest extends FormRequest
{
/**
* Determine if this request is via a many to many relationship.
*
* #return bool
*/
public function viaManyToMany();
/**
* Determine if this request is an attach or create request.
*
* #return bool
*/
public function isCreateOrAttachRequest();
/**
* Determine if this request is an update or update-attached request.
*
* #return bool
*/
public function isUpdateOrUpdateAttachedRequest();
/**
* Determine if this request is a resource index request.
*
* #return bool
*/
public function isResourceIndexRequest();
/**
* Determine if this request is a resource detail request.
*
* #return bool
*/
public function isResourceDetailRequest();
/**
* Determine if this request is an action request.
*
* #return bool
*/
public function isActionRequest();
}
Would've been nice if you can type hint the NovaRequest instead of the regular one in the Nova resource fields() method but it is not allowed due to the parent resource being extended.
You can create two separate fields for index & details page.
// ----- For Index page
Text::make('Preview', function () {
return \small_preview($this->image);
})
->onlyOnIndex()
->asHtml(),
// ----- For Detail page
Text::make('Preview', function () {
return \large_preview($this->image);
})
->onlyOnDetail()
->asHtml(),

PHPUnit: How do I mock an EntityManager without mocking the Metadata?

Working with PHPUnit and Doctrine I frequently end up writing very large methods for mocking Doctrines ClassMetadata, although in my opinion it does not need to be mocked, because it can be seen as stable. Still I need to mock the EntityManager because I don't want Doctrine to connect to a database.
So here's my question: How do I get my ClassMetadata via the EntityManager mock without needing a database connection? For all eventual database calls the EntityManager still needs to be a mock, I just don't want to write all my metadata down again.
I'm using the DoctrineModule for Zend 2 so it would be useful to be able to use my configuration to get the Metadata object, but I assume it's also ok to read the required sections manually.
Example:
public function testGetUniqueFields()
{
$this->prepareGetUniqueFields(); // about 50 lines of mocking ClassMetadata
$entity = 'UniqueWithoutAssociation';
$unique = $this->handler->getUniqueFields($entity);
$expected = ["uniqueColumn"];
$this->assertEquals($expected, $unique,
'getUniqueFields does not return the unique fields');
}
And the code of the actual class:
public function getUniqueFields($class)
{
$unique = array();
$metadata = $this->getClassMetadata($class);
$fields = $metadata->getFieldNames();
foreach ($fields as $field) {
if($metadata->isUniqueField($field) && !$metadata->isIdentifier($field)) {
$unique[] = $field;
}
}
return $unique;
}
The test works like expected, but every time I test another method or another behavior of the method, I need to prepare the mocks again or combine past definitions. Plus, the 50 lines I need for this code are the least I have in this test. Most of the test class is all about the ClassMetadata mock. It is a time consuming and - if you see ClassMetadata as a stable component - unnecessary work.
After spending many hours starring at the Doctrine source code, I found a solution.
Once again, this solution is only if you are working with Doctrines ClassMetadata object so often that it becomes unclean to mock every method call. In every other case you should still create a mock of ClassMetadata.
Still, since the composers minimum stability setting was set to stable, such components can be seen as stable so there is no absolute need to create a mock object.
ClassMetadata depends on several other Doctrine classes, which are all injected through the ubiquitous EntityManager:
Doctrine\ORM\Configuration to get the entity path
Doctrine\Common\Annotations\AnnotationReader and Doctrine\ORM\Mapping\Driver\AnnotationDriver injected through the Configuration object
Doctrine\DBAL\Connection to get the database platform in order to know about the identifier strategy. This object should be mocked so no database calls are possible
Doctrine\DBAL\Platforms\AbstractPlatform as mentioned
Doctrine\Common\EventManager to trigger some events
For single test methods or simple method calls I created a method returning an EntityManager mock object that is capable of returning a valid ClassMetadata object:
/**
* #return EntityManager|\PHPUnit_Framework_MockObject_MockObject
*/
public function getEmMock()
{
$dir = __DIR__."/Asset/Entity/";
$config = Setup::createAnnotationMetadataConfiguration(array($dir), true);
$eventManager = new \Doctrine\Common\EventManager();
$platform = new PostgreSqlPlatform();
$metadataFactory = new ClassMetadataFactory();
$config->setMetadataDriverImpl(new AnnotationDriver(new AnnotationReader()));
$connectionMock = $this->getMockBuilder('Doctrine\DBAL\Connection')
->disableOriginalConstructor()
->getMock();
$connectionMock->expects($this->any())
->method('getDatabasePlatform')
->will($this->returnValue($platform));
/** #var EntityManager|\PHPUnit_Framework_MockObject_MockObject $emMock */
$emMock = $this->getMockBuilder('Doctrine\ORM\EntityManager')
->disableOriginalConstructor()
->getMock();
$metadataFactory->setEntityManager($emMock);
$emMock->expects($this->any())
->method('getConfiguration')
->will($this->returnValue($config));
$emMock->expects($this->any())
->method('getConnection')
->will($this->returnValue($connectionMock));
$emMock->expects($this->any())
->method('getEventManager')
->will($this->returnValue($eventManager));
$emMock->expects($this->any())
->method('getClassMetadata')
->will($this->returnCallback(function($class) use ($metadataFactory){
return $metadataFactory->getMetadataFor($class);
}));
return $emMock;
}
Here you could even manipulate all objects by calling their getters created for the EntityManager mock. But that wouldn't be exactly clean and the method remains inflexible in some cases. Still a simple solution and you could e.g. add some parameters and put the method in a trait to reuse it.
For further needs, I created an abstract class that offers a maximum of flexibility and allows you to mock everything else or create some components in a whole other way.
It needs two configurations: The entity path and the platform object. You can manipulate or replace any object by setting it in the setUp method and then get the required EntityManager mock with getEmMock().
A little bit larger, but here it is:
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\EventManager;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\ORM\Configuration;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\ClassMetadataFactory;
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
use Doctrine\ORM\Tools\Setup;
/**
* Class AbstractTestWithMetadata
* #author Marius Teller
*/
abstract class AbstractTestWithMetadata extends \PHPUnit_Framework_TestCase
{
const EXCEPTION_NO_ENTITY_PATHS_SET = "At least one entity path must be set";
const EXCEPTION_NO_PLATFORM_SET = "An instance of Doctrine\\DBAL\\Platforms\\AbstractPlatform must be set";
/**
* #var array
*/
protected $entityPaths = [];
/**
* #var AbstractPlatform
*/
protected $platform;
/**
* #var EntityManager
*/
protected $emMock;
/**
* #var Connection
*/
protected $connectionMock;
/**
* #var Configuration
*/
protected $configuration;
/**
* #var EventManager
*/
protected $eventManager;
/**
* #var ClassMetadataFactory
*/
protected $classMetadataFactory;
/**
* #return array
* #throws \Exception
*/
public function getEntityPaths()
{
if($this->entityPaths === []) {
throw new \Exception(self::EXCEPTION_NO_ENTITY_PATHS_SET);
}
return $this->entityPaths;
}
/**
* #param array $entityPaths
*/
public function setEntityPaths(array $entityPaths)
{
$this->entityPaths = $entityPaths;
}
/**
* add an entity path
* #param string $path
*/
public function addEntityPath($path)
{
$this->entityPaths[] = $path;
}
/**
* #return AbstractPlatform
* #throws \Exception
*/
public function getPlatform()
{
if(!isset($this->platform)) {
throw new \Exception(self::EXCEPTION_NO_PLATFORM_SET);
}
return $this->platform;
}
/**
* #param AbstractPlatform $platform
*/
public function setPlatform(AbstractPlatform $platform)
{
$this->platform = $platform;
}
/**
* #return EntityManager
*/
public function getEmMock()
{
if(!isset($this->emMock)) {
/** #var EntityManager|\PHPUnit_Framework_MockObject_MockObject $emMock */
$emMock = $this->getMockBuilder('Doctrine\ORM\EntityManager')
->disableOriginalConstructor()
->getMock();
$config = $this->getConfiguration();
$connectionMock = $this->getConnectionMock();
$eventManager = $this->getEventManager();
$classMetadataFactory = $this->getClassMetadataFactory();
$classMetadataFactory->setEntityManager($emMock);
$emMock->expects($this->any())
->method('getConfiguration')
->will($this->returnValue($config));
$emMock->expects($this->any())
->method('getConnection')
->will($this->returnValue($connectionMock));
$emMock->expects($this->any())
->method('getEventManager')
->will($this->returnValue($eventManager));
$emMock->expects($this->any())
->method('getClassMetadata')
->will($this->returnCallback(function($class) use ($classMetadataFactory){
return $classMetadataFactory->getMetadataFor($class);
}));
$this->setEmMock($emMock);
}
return $this->emMock;
}
/**
* #param EntityManager $emMock
*/
public function setEmMock($emMock)
{
$this->emMock = $emMock;
}
/**
* #return Connection
*/
public function getConnectionMock()
{
if(!isset($this->connectionMock)) {
$platform = $this->getPlatform();
/** #var Connection|\PHPUnit_Framework_MockObject_MockObject $connectionMock */
$connectionMock = $this->getMockBuilder('Doctrine\DBAL\Connection')
->disableOriginalConstructor()
->getMock();
$connectionMock->expects($this->any())
->method('getDatabasePlatform')
->will($this->returnValue($platform));
$this->setConnectionMock($connectionMock);
}
return $this->connectionMock;
}
/**
* #param Connection $connectionMock
*/
public function setConnectionMock($connectionMock)
{
$this->connectionMock = $connectionMock;
}
/**
* #return Configuration
*/
public function getConfiguration()
{
if(!isset($this->configuration)) {
$config = Setup::createAnnotationMetadataConfiguration($this->getEntityPaths(), true);
$config->setMetadataDriverImpl(new AnnotationDriver(new AnnotationReader()));
$this->setConfiguration($config);
}
return $this->configuration;
}
/**
* #param Configuration $configuration
*/
public function setConfiguration(Configuration $configuration)
{
$this->configuration = $configuration;
}
/**
* #return EventManager
*/
public function getEventManager()
{
if(!isset($this->eventManager)) {
$this->setEventManager(new EventManager());
}
return $this->eventManager;
}
/**
* #param EventManager $eventManager
*/
public function setEventManager($eventManager)
{
$this->eventManager = $eventManager;
}
/**
* #return ClassMetadataFactory
*/
public function getClassMetadataFactory()
{
if(!isset($this->classMetadataFactory)) {
$this->setClassMetadataFactory(new ClassMetadataFactory());
}
return $this->classMetadataFactory;
}
/**
* #param ClassMetadataFactory $classMetadataFactory
*/
public function setClassMetadataFactory(ClassMetadataFactory $classMetadataFactory)
{
$this->classMetadataFactory = $classMetadataFactory;
}
}
One more hint: You might have problems with annotations of other classes, e.g. Zend\Form\Annotation\Validator. Such annotations will throw an exception in Doctrines parser because this parser does not use auto loading and only checks for already loaded classes. So if you still want to use them, you just have to include them manually before parsing the classes annotations.

Enable print order functionality for guest Magento

i need to enable the print order functionality for guest checkout.
for logged in users the print functionality is working fine
but for guest users the print button was not visible on success page
to show print button i have remove the check in file succcess.phtml
<?php if ($this->getCanViewOrder() && $this->getCanPrintOrder()) :?>
<p>
<?php echo $this->__('Click here to print a copy of your order confirmation.', $this->getPrintUrl()) ?>
<?php echo $this->getChildHtml() ?>
</p>
<?php endif;?>
now the print button is visible for guest also but when i click on
that it ask for login.
I need to show the print order for guest also without login.
the print order location is like
localhost/magento1.9/index.php/sales/order/print/order_id/8/
i have check the
/var/www/magento1.9/app/code/core/Mage/Sales/Controller/Abstract.php
and find print action which is as
public function printAction()
{
if (!$this->_loadValidOrder()) {
return;
}
$this->loadLayout('print');
$this->renderLayout();
}
but i cant understand how to make print functionality available for guest without login.
Please suggest me thanks in advance
You should try this extension: https://github.com/eltrino/PrintOrder It works very nicely and is a save way to offere print-links to the order confirmations after a guest checkout.
In Magento 2:
you have to override the module Sales and then overwrite the 2 following Controllers like that:
app/code/YourVendorName/Sales/etc/di.xml
<preference for="Magento\Sales\Controller\Order\PrintAction" type="YourVendorNAme\Sales\Controller\Order\PrintAction"/>
<preference for="Magento\Sales\Controller\AbstractController\OrderLoader" type="YourVendorNAme\Sales\Controller\AbstractController\OrderLoader"/>
app/code/YourVendorName/Sales/Controller/AbstractController/OrderLoader.php
<?php
namespace YourVendorNAme\Sales\Controller\AbstractController;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\Controller\Result\Forward;
use Magento\Framework\Controller\Result\Redirect;
use Magento\Framework\Registry;
use Magento\Framework\Controller\Result\ForwardFactory;
use Magento\Framework\Controller\Result\RedirectFactory;
class OrderLoader implements \Magento\Sales\Controller\AbstractController\OrderLoaderInterface
{
/**
* #var \Magento\Sales\Model\OrderFactory
*/
protected $orderFactory;
/**
* #var \Magento\Framework\Registry
*/
protected $registry;
/**
* #var \Magento\Sales\Controller\AbstractController\OrderViewAuthorizationInterface
*/
protected $orderAuthorization;
/**
* #var \Magento\Framework\UrlInterface
*/
protected $url;
/**
* #var ForwardFactory
*/
protected $resultForwardFactory;
/**
* #var RedirectFactory
*/
protected $redirectFactory;
private $checkoutSession;
/**
* #param \Magento\Sales\Model\OrderFactory $orderFactory
* #param OrderViewAuthorizationInterface $orderAuthorization
* #param Registry $registry
* #param \Magento\Framework\UrlInterface $url
* #param ForwardFactory $resultForwardFactory
* #param RedirectFactory $redirectFactory
*/
public function __construct(
\Magento\Sales\Model\OrderFactory $orderFactory,
\Magento\Sales\Controller\AbstractController\OrderViewAuthorizationInterface $orderAuthorization,
Registry $registry,
\Magento\Framework\UrlInterface $url,
ForwardFactory $resultForwardFactory,
RedirectFactory $redirectFactory,
\Magento\Checkout\Model\Session $checkoutSession
) {
$this->orderFactory = $orderFactory;
$this->orderAuthorization = $orderAuthorization;
$this->registry = $registry;
$this->url = $url;
$this->resultForwardFactory = $resultForwardFactory;
$this->redirectFactory = $redirectFactory;
$this->checkoutSession = $checkoutSession;
}
/**
* #param RequestInterface $request
* #return bool|Forward|Redirect
*/
public function load(RequestInterface $request)
{
$orderId = (int)$request->getParam('order_id');
if (!$orderId) {
/** #var Forward $resultForward */
$resultForward = $this->resultForwardFactory->create();
return $resultForward->forward('noroute');
}
$order = $this->orderFactory->create()->load($orderId);
$lastOrderId = $this->checkoutSession->getData('last_order_id');
// Print order if customer is logged in or it's the last order of guest customer
if ($this->orderAuthorization->canView($order) || $lastOrderId == $orderId) {
$this->registry->register('current_order', $order);
return true;
}
/** #var Redirect $resultRedirect */
$resultRedirect = $this->redirectFactory->create();
return $resultRedirect->setUrl($this->url->getUrl('*/*/history'));
}
}
app/code/YourVendorName/Sales/Controller/Order/PrintAction.php
<?php
namespace YourVendorNAme\Sales\Controller\Order;
use Magento\Framework\App\ResponseInterface;
use Magento\Framework\Controller\ResultInterface;
use Magento\Framework\View\Result\Page;
use Magento\Sales\Controller\OrderInterface;
class PrintAction extends \Magento\Sales\Controller\AbstractController\PrintAction implements OrderInterface
{
/**
* #return ResponseInterface|ResultInterface|Page
*/
public function execute()
{
$result = $this->orderLoader->load($this->_request);
if ($result instanceof ResultInterface) {
return $result;
}
/** #var Page $resultPage */
$resultPage = $this->resultPageFactory->create();
$resultPage->addHandle('print');
return $resultPage;
}
}

ZF2: DB\AbstractTableGateway: How to use JOIN?

I new in ZF and have a code located below. I try get custom colums and join in sql select, but it failed.
I tried to use the search but found no results.
Tell me examples of how to do more complex queries.
Thanks.
<?php
namespace FcFlight\Model;
use Zend\Db\TableGateway\AbstractTableGateway;
use Zend\Db\Adapter\Adapter;
use Zend\Db\ResultSet\ResultSet;
use Zend\Db\Sql\Select;
use FcFlight\Filter\FlightHeaderFilter;
class FlightHeaderModel extends AbstractTableGateway
{
/**
* #var string
*/
protected $table = 'flightBaseHeaderForm';
/**
* #param \Zend\Db\Adapter\Adapter $adapter
*/
public function __construct(Adapter $adapter)
{
$this->adapter = $adapter;
$this->resultSetPrototype = new ResultSet();
$this->resultSetPrototype->setArrayObjectPrototype(new FlightHeaderFilter($this->adapter));
$this->initialize();
}
/**
* #param $id
* #return array|\ArrayObject|null
* #throws \Exception
*/
public function get($id)
{
$id = (int)$id;
$rowSet = $this->select(array('id' => $id));
$row = $rowSet->current();
if (!$row) {
throw new \Exception("Could not find row $id");
}
$row->dateOrder = date('Y-m-d', $row->dateOrder);
return $row;
}
}
Since you are using the tableGateway, you must get an instance of Sql(): $this->getSql();
With that instance you will create an instance of Select, which will then let you perform a join:
$sql = $this->getSql();
$select = $sql->select();
$select->join('TableNameToJoin', 'MainColumnA = JoinColumnA');
Then to execute the query, you call selectWith on your tableGateway:
$this->selectWith($select);
If you wish to customize the join further, you can pass two more arugments:
An array of columns you wish to select
The type of join you wish to do (LEFT JOIN for example)
You can also add an alias to the table you are joining on by passing an Array as the table name, with the key of the array being the alias and the value being the table name.
$select->join(['Alias' => 'TableNameToJoin'], 'MainColumnA = Alias.JoinColumnA', ['ColumnA', 'ColumnB'], $select::JOIN_LEFT);

Resources