DDD in SF3 folder structure - php

I am thinking through an ad website where Users can login, post new Listings and search existing ones. I am going to make this my first project following DDD principles completely. I have never done any DDD in Symfony before.
Below are my thoughts about this. Could you please tell me if this is correct and advice on better ways?
I can see two domains: User and Listing
Searching/displaying/posting functionality will live in Listing domain. Logging in/out live in a User domain.
SF3 directory example structure is
app/
ListingBundle/
src/
Listing.php
SearchService.php
ListingRepositoryInterface.php
Controller/
public/
ListingController.php
protected/
ListingController.php
Resource/
view/
public/
detail.twig.html
protected/
edit.twig.html
UserBundle/
src/
User.php
AuthService.php
UserRepositoryInterface.php
Controller/
public/
UserController.php
protected/
UserController.php
Resource/
view/
public/
login.twig.html
protected/
dashboard.twig.html
PersistenceBundle
src/
UserRepository.php
ListingRepository.php
My main questions are:
Is this structure correct?
Is it a good idea to have separate protected and public controllers with the same name?
Where do things go like a page on the User backend part of the website showing recent Listings posted by the User? Where is the boundary between those two domains?
Is PersistenceBundle a good idea or should I have persistence live inside User and Listing bundle?

Frameworks & DDD
You make a wrong assumption here, which is "I am going to use the Symfony framework to implement my app in a DDD-ish way".
Don't do this, Frameworks are just an implementation detail and provide one (ore more) delivery methods for your Application. And I mean Application here in the context of the Hexagonal Architecture.
If you look at the following example from one of our contexts you see that our ApiClient context contains three layers (top-level directory structure). Application (contains the use case services), Domain (contains the models and behaviour) and Infrastructure (contains infrastructure concerns like persistence and delivery). I focused on the Symfony integration and the persistence here, since this is what the OP's original question was about:
src/ApiClient
├── Application
│   ├── ApiClient
│   │   ├── CreateApiClient
│   │   ├── DisableApiClient
│   │   ├── EnableApiClient
│   │   ├── GetApiClient
│   │   ├── ListApiClient
│   │   ├── RemoveApiClient
│   │   └── ChangeApiClientDetails
│   ├── ClientIpAddress
│   │   ├── BlackListClientIpAddress
│   │   ├── CreateClientIpAddress
│   │   ├── ListByApiClientId
│   │   ├── ListClientIpAddresses
│   │   └── WhiteListClientIpAddress
│   └── InternalContactPerson
│   ├── CreateInternalContactPerson
│   ├── GetInternalContactPerson
│   ├── GetByApiClientId
│   ├── ListContacts
│   ├── ReassignApiClient
│   └── Remove
├── Domain
│   └── Model
│   ├── ApiClient
│   ├── ClientIpAddress
│   └── InternalContactPerson
└── Infrastructure
├── Delivery
│   └── Http
│   └── SymfonyBundle
│   ├── Controller
│   │   ├── ApiClientController.php
│   │   ├── InternalContactController.php
│   │   └── IpAddressController.php
│   ├── DependencyInjection
│   │   ├── Compiler
│   │   │   ├── EntityManagerPass.php
│   │   │   └── RouterPass.php
│   │   ├── Configuration.php
│   │   ├── MetadataLoader
│   │   │   ├── Adapter
│   │   │   │   ├── HateoasSerializerAdapter.php
│   │   │   │   └── JMSSerializerBuilderAdapter.php
│   │   │   ├── Exception
│   │   │   │   ├── AmbiguousNamespacePathException.php
│   │   │   │   ├── EmptyMetadataDirectoryException.php
│   │   │   │   ├── FileException.php
│   │   │   │   ├── MalformedNamespaceException.php
│   │   │   │   └── MetadataLoadException.php
│   │   │   ├── FileMetadataLoader.php
│   │   │   ├── MetadataAware.php
│   │   │   └── MetadataLoaderInterface.php
│   │   └── MFBApiClientExtension.php
│   ├── DTO
│   │   └── ApiClient
│   │   └── ChangeInternalContact
│   │   ├── ChangeInternalContactRequest.php
│   │   └── ChangeInternalContactResponse.php
│   ├── MFBApiClientBundle.php
│   ├── Resources
│   │   ├── config
│   │   │   ├── domain_services.yml
│   │   │   ├── metadata_loader.yml
│   │   │   ├── routing.yml
│   │   │   └── services.yml
│   │   ├── hateoas
│   │   │   └── ApiClient
│   │   │   ├── Application
│   │   │   │   ├── ApiClient
│   │   │   │   │   ├── CreateApiClient
│   │   │   │   │   │   └── CreateApiClientResponse.yml
│   │   │   │   │   └── ListApiClient
│   │   │   │   │   └── ListApiClientResponse.yml
│   │   │   │   ├── ClientIpAddress
│   │   │   │   │   ├── CreateClientIpAddress
│   │   │   │   │   │   └── CreateClientIpAddressResponse.yml
│   │   │   │   │   ├── ListByApiClientId
│   │   │   │   │   │   └── ListByApiClientIdResponse.yml
│   │   │   │   │   └── ListClientIpAddresses
│   │   │   │   │   └── ListClientIpAddressesResponse.yml
│   │   │   │   └── InternalContactPerson
│   │   │   │   ├── Create
│   │   │   │   │   └── CreateResponse.yml
│   │   │   │   └── List
│   │   │   │   └── ListResponse.yml
│   │   │   └── Domain
│   │   │   ├── ApiClient
│   │   │   │   └── ApiClient.yml
│   │   │   ├── ClientIpAddress
│   │   │   │   └── ClientIpAddress.yml
│   │   │   └── InternalContactPerson
│   │   │   └── InternalContactPerson.yml
│   │   └── serializer
│   │   ├── ApiClient
│   │   │   ├── Application
│   │   │   │   ├── ApiClient
│   │   │   │   │   ├── CreateApiClient
│   │   │   │   │   │   ├── ContactPersonRequest.yml
│   │   │   │   │   │   ├── CreateApiClientRequest.yml
│   │   │   │   │   │   └── CreateApiClientResponse.yml
│   │   │   │   │   └── GetApiClient
│   │   │   │   │   └── GetApiClientResponse.yml
│   │   │   │   ├── ClientIpAddress
│   │   │   │   │   └── CreateClientIpAddress
│   │   │   │   │   ├── CreateClientIpAddressRequest.yml
│   │   │   │   │   └── CreateClientIpAddressResponse.yml
│   │   │   │   └── InternalContactPerson
│   │   │   │   ├── Create
│   │   │   │   │   ├── CreateRequest.yml
│   │   │   │   │   └── CreateResponse.yml
│   │   │   │   ├── Get
│   │   │   │   │   └── GetResponse.yml
│   │   │   │   ├── List
│   │   │   │   │   └── ListResponse.yml
│   │   │   │   └── ReassignApiClient
│   │   │   │   └── ReassignApiClientRequest.yml
│   │   │   └── Domain
│   │   │   ├── ApiClient
│   │   │   │   ├── ApiClient.yml
│   │   │   │   └── ContactPerson.yml
│   │   │   ├── ClientIpAddress
│   │   │   │   └── ClientIpAddress.yml
│   │   │   └── InternalContactPerson
│   │   │   └── InternalContactPerson.yml
│   │   └── Bundle
│   │   └── DTO
│   │   └── ApiClient
│   │   └── ChangeInternalContact
│   │   └── ChangeInternalContactRequest.yml
│   └── Service
│   └── Hateoas
│   └── UrlGenerator.php
└── Persistence
├── Doctrine
│   ├── ApiClient
│   │   ├── ApiClientRepository.php
│   │   └── mapping
│   │   ├── ApiClientId.orm.yml
│   │   ├── ApiClient.orm.yml
│   │   ├── CompanyName.orm.yml
│   │   ├── ContactEmail.orm.yml
│   │   ├── ContactList.orm.yml
│   │   ├── ContactName.orm.yml
│   │   ├── ContactPerson.orm.yml
│   │   ├── ContactPhone.orm.yml
│   │   └── ContractReference.orm.yml
│   ├── ClientIpAddress
│   │   ├── ClientIpAddressRepository.php
│   │   └── mapping
│   │   ├── ClientIpAddressId.orm.yml
│   │   ├── ClientIpAddress.orm.yml
│   │   └── IpAddress.orm.yml
│   └── InternalContactPerson
│   ├── InternalContactPersonRepository.php
│   └── mapping
│   ├── InternalContactPersonId.orm.yml
│   └── InternalContactPerson.orm.yml
└── InMemory
├── ApiClient
│   └── ApiClientRepository.php
├── ClientIpAddress
│   └── ClientIpAddressRepository.php
└── InternalContactPerson
└── InternalContactPersonRepository.php
94 directories, 145 files
Quite a lot of files!
You can see that I am using the bundle as a Port of the Application (the naming is a little bit of though, it should not be Http delivery, since in the strict sense of the Hexagonal Architecture it is an App-To-App Port). I strongly advise you to read the DDD in PHP book where all these concepts are actually explained with expressive examples in PHP (assuming you have read the blue book and the red book already, although this book works as a standalone while still making references).

A folder structure for DDD applications built with Symfony
I second tPl0ch's answer, but would like to propose a slight variant of the folder structure which has been useful in a couple of projects with Symfony where I was involved in. For your specific domain the folder structure could look as follows:
app
Listing
Domain
Model
Listing.php
Repository
ListingRepository.php
Service
SearchService.php
Infrastructure
Repository
DoctrineListingRepository.php // or some other implementation
Resources
// symfony & doctrine config etc.
Service
ElasticSearchService.php // or some other implementation
ListingInfrastructureBundle.php
Presentation
Controller
ViewListingController.php // assuming this is the "public" part
EditListingController.php // assuming this is the "protected" part
Forms
ListingForm.php
Resources
// symfony config & views etc.
ListingPresentationBundle.php
User
// ...
Infrastructure
Service
AuthService.php
// ...
With this folder structure, you separate the different layers of the onion architecture. The different folders clearly communicate the boundaries and allowed dependencies between the layers. I have written a blog post on DDD folder structures with Symfony which describes the approach in detail.
Additional Resources:
Apart from that, I also recommend to have a look at the following resources:
PHP DDD Cargo Sample: PHP 7 Version of the cargo sample used in Eric Evans DDD book
Sylius: eCommerce PHP framework built on top of Symfony with component-based architecture
I have learned a lot from understanding the Sylius code base - it is a real world project and is fairly huge. They have all kinds of tests and have put a lot of effort into shipping high quality code.

Related

Ajax Call from React to a PHP file - don't know location

Im creating a very basic login page and i'm trying to use php to verify the user login. Here is the code I'm using to access the php file.
axios.post("login.php", {
user: 'Fred',
pass: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
The PHP file is located within the src folder of the react app.
── src
│   ├── components
│   │   ├── BrowsePage
│   │   │   ├── BrowsePage.css
│   │   │   ├── BrowsePage.js
│   │   │   └── default.jpg
│   │   ├── CreatePage
│   │   │   ├── CreatePage.css
│   │   │   └── CreatePage.js
│   │   ├── Header
│   │   │   ├── Header.css
│   │   │   └── Header.js
│   │   ├── LoginPage
│   │   │   ├── LoginPage.css
│   │   │   ├── LoginPage.js
│   │   │   └── logo.svg
│   │   ├── ProfilePage
│   │   │   ├── ProfilePage.css
│   │   │   └── ProfilePage.js
│   │   └── RecPage
│   │   ├── default.jpg
│   │   ├── RecPage.css
│   │   └── RecPage.js
│   ├── index.css
│   ├── index.js
│   ├── login.php
│   └── registerServiceWorker.js
When I make the call it logs
xhr.js:178 POST http://localhost:3000/login.php 404 (Not Found)
The current path to the php document does not work, and none of the others I've tried work. What is the path to make an axios call to this php document?
You'll need to setup a server locally that your React application can proxy certain http requests to. This server will run your login.php script and authenticate the username/password. create-react-app looks for a proxy value in your package.json and tells webpack-dev-server to forward any calls to api/foobar to wherever you have declared that your back-end will be running.
In your package.json add:
"proxy": "http://localhost:8000"
This tells React to forward requests made to http://localhost:3000/api/login to http://localhost:8000/api/login
Then modify your axios call to look like this
axios.post("/api/login", ..., ...).then()
Next, you have to get your PHP server running on http://localhost:8000 and set up your server application to handle POST requests made to /api/login.
I'm not a PHP guy but I've heard Laravel is nice to work with. It would be easier if your PHP backend was in its own directory completely.

How to use Controller and Model in slim php framework with example

I have just got Slim PHP Framework with composer. Can anyone suggest me how to use Controller and Model in slim framework. And Where to put controllers and model in slim framework.Actually I want to use slim framework only for API. And I want to use controller for it. I have read its document but I am not able to find regarding controller and models.
Slim doesn't enforce any particular layout for your application.
I tend to like to separate out PHP source from HTML templates, so I use this pattern (taken from slim-bookshelf):
app/
├── src
│   ├── Bookshelf
│   │   ├── Author.php
│   │   ├── AuthorController.php
│   │   ├── Book.php
│   │   ├── BookController.php
│   │   └── TwigExtension.php
│   ├── dependencies.php
│   ├── middleware.php
│   └── routes.php
├── templates
│   ├── bookshelf
│   │   ├── author
│   │   │   ├── books.twig
│   │   │   ├── edit.twig
│   │   │   └── list.twig
│   │   └── book
│   │   └── list.twig
│   └── layout.twig
└── settings.php
However, my APIs do not have templates, so I move everything up a level. This example comes from slim-bookshelf-api and uses a separate class for each route's action rather than a controller class:
src
├── App
│   └── Action
│   ├── HomeAction.php
│   └── PingAction.php
├── Bookshelf
│   ├── Action
│   │   ├── CreateAuthorAction.php
│   │   ├── DeleteAuthorAction.php
│   │   ├── EditAuthorAction.php
│   │   ├── GetAuthorAction.php
│   │   └── ListAuthorsAction.php
│   ├── Author.php
│   ├── AuthorMapper.php
│   └── AuthorTransformer.php
├── dependencies.php
├── middleware.php
├── routes.php
└── settings.php

Problems trying to use Slim 3 with Doctrine 2

I get the following message:
Slim Application Error
The application could not run because of the following error:
Details
Type: Error
Message: Class 'App\Action\InterventionsAction' not found
File: /var/www/html/ws_slim/public/index.php
Line: 53
Trace
#0 [internal function]: Closure->{closure}(Object(Slim\Http\Request), Object(Slim\Http\Response), Array)
#1 /var/www/html/ws_slim/vendor/slim/slim/Slim/Handlers/Strategies/RequestResponse.php(41): call_user_func(Object(Closure), Object(Slim\Http\Request), Object(Slim\Http\Response), Array)
#2 /var/www/html/ws_slim/vendor/slim/slim/Slim/Route.php(344): Slim\Handlers\Strategies\RequestResponse->__invoke(Object(Closure), Object(Slim\Http\Request), Object(Slim\Http\Response), Array)
#3 /var/www/html/ws_slim/vendor/slim/slim/Slim/MiddlewareAwareTrait.php(122): Slim\Route->__invoke(Object(Slim\Http\Request), Object(Slim\Http\Response))
#4 /var/www/html/ws_slim/vendor/slim/slim/Slim/Route.php(316): Slim\Route->callMiddlewareStack(Object(Slim\Http\Request), Object(Slim\Http\Response))
#5 /var/www/html/ws_slim/vendor/slim/slim/Slim/App.php(476): Slim\Route->run(Object(Slim\Http\Request), Object(Slim\Http\Response))
#6 /var/www/html/ws_slim/vendor/slim/slim/Slim/MiddlewareAwareTrait.php(122): Slim\App->__invoke(Object(Slim\Http\Request), Object(Slim\Http\Response))
#7 /var/www/html/ws_slim/vendor/slim/slim/Slim/App.php(370): Slim\App->callMiddlewareStack(Object(Slim\Http\Request), Object(Slim\Http\Response))
#8 /var/www/html/ws_slim/vendor/slim/slim/Slim/App.php(295): Slim\App->process(Object(Slim\Http\Request), Object(Slim\Http\Response))
#9 /var/www/html/ws_slim/public/index.php(59): Slim\App->run()
#10 {main}
My index file is like this:
<?php
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
use App\Action\InterventionsAction;
require 'vendor/autoload.php';
$app = new \Slim\App([
'settings' => [
'displayErrorDetails' => true
]
]);
$app->get('/hello/{name}', function (Request $request, Response $response) {
$name = $request->getAttribute('name');
$response->getBody()->write("Hello,, $name");
return $response;
});
$app->get('/api/interventions', function (Request $request, Response $response) {
$int = new InterventionsAction($em);
$response->getBody()->write("Hello,, ");
return $response;
});
$app->run();
and InterventionsAction is like this:
<?php
namespace App\Action;
use Doctrine\ORM\EntityManager;
final class InterventionsAction
{
private $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function fetch($request, $response, $args)
{
$interventions = $this->em->getRepository('App\Entity\Interventions')->findAll();
$interventions = array_map(
function ($interventions) {
return $interventions->getArrayCopy();
},
$interventions
);
return $response->withJSON($interventions);
}
}
File Tree:
├── cli-config.php
├── composer.json
├── composer.lock
├── CONTRIBUTING.md
├── EXPORT
│   ├── Companies.php
│   ├── CompaniesPlansPayments.php
│   ├── CompaniesPlans.php
│   ├── DepartmentsCoordinators.php
│   ├── Departments.php
│   ├── InterventionclasificationDetails.php
│   ├── Interventionclasifications.php
│   ├── Interventionrelations.php
│   ├── Interventions.php
│   ├── InterventiontypesCompanies.php
│   ├── Interventiontypes.php
│   ├── Locations.php
│   ├── LocationTypes.php
│   ├── Managementreview.php
│   ├── Managementreviewrelations.php
│   ├── Plans.php
│   ├── ServicelinesManagers.php
│   ├── Servicelines.php
│   ├── Users.php
│   └── Usertypes.php
├── logs
│   ├── app.log
│   └── README.md
├── nbproject
│   ├── private
│   │   └── private.properties
│   ├── project.properties
│   └── project.xml
├── phpunit.xml
├── public
│   └── index.php
├── README.md
├── src
│   ├── Action
│   │   └── InterventionsAction.php
│   ├── dependencies.php
│   ├── Entity
│   │   ├── Companies.php
│   │   ├── CompaniesPlansPayments.php
│   │   ├── CompaniesPlans.php
│   │   ├── DepartmentsCoordinators.php
│   │   ├── Departments.php
│   │   ├── InterventionclasificationDetails.php
│   │   ├── Interventionclasifications.php
│   │   ├── Interventionrelations.php
│   │   ├── Interventions.php
│   │   ├── InterventiontypesCompanies.php
│   │   ├── Interventiontypes.php
│   │   ├── Locations.php
│   │   ├── LocationTypes.php
│   │   ├── Managementreview.php
│   │   ├── Managementreviewrelations.php
│   │   ├── Plans.php
│   │   ├── ServicelinesManagers.php
│   │   ├── Servicelines.php
│   │   ├── Users.php
│   │   └── Usertypes.php
│   ├── middleware.php
│   ├── routes.php
│   └── settings.php
├── templates
│   └── index.phtml
├── tests
│   └── Functional
│   ├── BaseTestCase.php
│   └── HomepageTest.php
└── vendor
├── autoload.php
├── bin
│   ├── doctrine -> ../doctrine/orm/bin/doctrine
│   ├── doctrine-dbal -> ../doctrine/dbal/bin/doctrine-dbal
│   ├── doctrine.php -> ../doctrine/orm/bin/doctrine.php
│   └── phpunit -> ../phpunit/phpunit/phpunit
├── composer
│   ├── autoload_classmap.php
│   ├── autoload_files.php
│   ├── autoload_namespaces.php
│   ├── autoload_psr4.php
│   ├── autoload_real.php
│   ├── ClassLoader.php
│   ├── installed.json
│   └── LICENSE
├── container-interop
│   └── container-interop
├── doctrine
│   ├── annotations
│   ├── cache
│   ├── collections
│   ├── common
│   ├── dbal
│   ├── inflector
│   ├── instantiator
│   ├── lexer
│   └── orm
├── monolog
│   └── monolog
├── myclabs
│   └── deep-copy
├── nikic
│   └── fast-route
├── phpdocumentor
│   ├── reflection-common
│   ├── reflection-docblock
│   └── type-resolver
├── phpspec
│   └── prophecy
├── phpunit
│   ├── php-code-coverage
│   ├── php-file-iterator
│   ├── php-text-template
│   ├── php-timer
│   ├── php-token-stream
│   ├── phpunit
│   └── phpunit-mock-objects
├── pimple
│   └── pimple
├── psr
│   ├── container
│   ├── http-message
│   └── log
├── sebastian
│   ├── code-unit-reverse-lookup
│   ├── comparator
│   ├── diff
│   ├── environment
│   ├── exporter
│   ├── global-state
│   ├── object-enumerator
│   ├── recursion-context
│   ├── resource-operations
│   └── version
├── slim
│   ├── php-view
│   └── slim
├── symfony
│   ├── console
│   ├── debug
│   ├── polyfill-mbstring
│   └── yaml
└── webmozart
└── assert
So my question is maybe I setted bad some configuration values or is there something missing I should be looking for?
I assume that your autoloader can't find the files. You should search for the "autoload" section in your composer.json and put something like the following in there:
"autoload": {
"psr-4: {
"App\\": "src/",
}
}
This assumes that your directory src/ only contains classes from the App-namespace. So src/Action/InterventionAction.php expects to contain a class with the namespace App\Action\InterventionAction. For your tests you might want to do the equivalent in the "autoload-dev"-section.
You will also have to run a composer install or composer update --lock to ensure the autoloader is updated with the new information.
You might also want to read the autoloading PSRs to know how to resolve file names to classes and the composer docs:
http://www.php-fig.org/psr/psr-0/ (outdated)
http://www.php-fig.org/psr/psr-4/
https://getcomposer.org/doc/04-schema.md#autoload

ZF2: Zend DB, TableGateway, Services Strategies

I have created a little Zend Framework 2 module called CMS to write simple articles in my site. This module follow uses Zend Db and the TableGateway class in order to get the data from the database.
I have read many website and books about the strategies to create a module and I prefer the short and fast way using these file structure:
.
├── Module.php
├── config
│   └── module.config.php
├── data
│   └── data.sql
├── src
│   └── Cms
│   ├── Controller
│   │   ├── IndexController.php
│   │   ├── PageAdminController.php
│   │   └── PageCategoryAdminController.php
│   ├── Form
│   │   ├── Element
│   │   │   ├── PageCategories.php
│   │   │   └── ParentPages.php
│   │   ├── PageCategoryFilter.php
│   │   ├── PageCategoryForm.php
│   │   ├── PageFilter.php
│   │   └── PageForm.php
│   ├── Hydrator
│   │   └── Strategy
│   │   └── DateTimeStrategy.php
│   ├── Model
│   │   ├── Page.php
│   │   ├── PageCategory.php
│   │   ├── PageCategoryTable.php
│   │   ├── PageTable.php
│   │   └── UrlRewrites.php
│   └── View
│   └── Helper
│   ├── Extract.php
│   └── Tags.php
└── view
└── cms
├── index
│   ├── index.phtml
│   ├── notfound.phtml
│   └── page.phtml
├── page-admin
│   ├── edit.phtml
│   └── index.phtml
├── page-category-admin
│   ├── edit.phtml
│   └── index.phtml
└── partial
└── tags.phtml
TableGateway Method
This file structure allows me to declare, for instance, the Page and PageTable class in the module.php and call the ServiceLocator to read and write the records from the database in this way:
$pageTable = $this->getServiceLocator()->get('PageTable');
In this case I can use this class to write the CRUD methods in the PageTable Class.
Inject Service Method
Then I have seen that there is a Service way to do the same thing where the CRUD actions are located in a Service Class that calls the TableGateway Class and inject by a Factory Class the Service into the __construct method of the Controller.
Service > TableGateway > Factory > Controller
Why have I to choose the Service strategy instead of the simple TableGateway?
Well your logic is a little off, the way is actually only
Controller calls Service calls TableGateway
The Factory is just a pattern to properly inject the dependencies.
Why use the Service
To abstract the behavior. The Service generally speaking is the instrument for your controllers to get the data. The Service then interacts with a data-source. What the data-source is, your controller doesn't care - hell not even your service should care. The service should only care for an implementation of an interface. This way, whenever you feel that you don't like TableGateway anymore but you wanna go Doctrine2, you don't have to change your Service. You don't have to change you Controller. All you have to change is the dependency of your Service. Instead of injecting a TableGateway class you inject your Doctrine2 class which matches the interface of the data-provider-dependency.

can't access vendor files and namespace on Zend Framework 2

I need to get my library from the vendor folder but i could not instantiate it from my controller. Whenever i try calling the classname it is not working and always result to
Fatal error: Class 'Sports\Database\Model\DropboxMapper' not found in /var/www/project1/module/Sportsui/src/Sportsui/Controller/DropboxController.php on line 33
my vendor directory looks like
vendor/
├── autoload.php
├── bin
│   ├── autoload_classmap.php
│   ├── classmap_generator.php -> ../zendframework/zendframework/bin/classmap_generator.php
│   ├── plugin_classmap.php
│   ├── pluginmap_generator.php -> ../zendframework/zendframework/bin/pluginmap_generator.php
│   └── templatemap_generator.php -> ../zendframework/zendframework/bin/templatemap_generator.php
├── composer
│   ├── autoload_classmap.php
│   ├── autoload_namespaces.php
│   ├── autoload_real.php
│   ├── ClassLoader.php
│   └── installed.json
├── mwGearman
├── README.md
├── Sports
│   ├── autoload_classmap.php
│   ├── library
│   │   └── Sports
│   │   ├── Database
│   │   │   └── Model
│   │   │   ├── DropboxMapper.php
│   │   │   ├── Entity
│   │   │   │   ├── Dropbox.php
│   │   │   │   ├── EntityAbstract.php
│   │   │   │   ├── SourceFields.php
│   │   │   │   └── Sources.php
│   │   │   ├── MapperAbstract.php
│   │   │   ├── SourceFieldsMapper.php
│   │   │   └── SourcesMapper.php
│   │   ├── FileSystemHandler.php
│   │   ├── Gearman
│   │   │   ├── Client.php
│   │   │   ├── DropboxClient.php
│   │   │   ├── DropboxWorker.php
│   │   │   ├── ValidatorClient.php
│   │   │   ├── ValidatorWorker.php
│   │   │   └── Worker.php
│   │   ├── Mvc
│   │   │   └── Controller
│   │   │   └── UtilsController.php
│   │   └── Utility
│   │   └── FileReader.php
│   └── Module.php
└── ZF2
Autoload classmapper that ZF2 has generated looks like this
<?php
// Generated by ZF2's ./bin/classmap_generator.php
return array(
'Sports\Module' => __DIR__ . '/Module.php',
'Sports\FileSystemHandler' => __DIR__ . '/library/Sports/FileSystemHandler.php',
'Sports\Database\Model\DropboxMapper' => __DIR__ . '/library/Sports/Database/Model/DropboxMapper.php',
'Sports\Database\Model\SourcesMapper' => __DIR__ . '/library/Sports/Database/Model/SourcesMapper.php',
'Sports\Database\Model\SourceFieldsMapper' => __DIR__ . '/library/Sports/Database/Model/SourceFieldsMapper.php',
'Sports\Database\Model\Entity\Dropbox' => __DIR__ . '/library/Sports/Database/Model/Entity/Dropbox.php',
'Sports\Database\Model\Entity\EntityAbstract' => __DIR__ . '/library/Sports/Database/Model/Entity/EntityAbstract.php',
'Sports\Database\Model\Entity\SourceFields' => __DIR__ . '/library/Sports/Database/Model/Entity/SourceFields.php',
'Sports\Database\Model\Entity\Sources' => __DIR__ . '/library/Sports/Database/Model/Entity/Sources.php',
'Sports\Database\Model\MapperAbstract' => __DIR__ . '/library/Sports/Database/Model/MapperAbstract.php',
'Sports\Mvc\Controller\UtilsController' => __DIR__ . '/library/Sports/Mvc/Controller/UtilsController.php',
'Sports\Gearman\ValidatorWorker' => __DIR__ . '/library/Sports/Gearman/ValidatorWorker.php',
'Sports\Gearman\ValidatorClient' => __DIR__ . '/library/Sports/Gearman/ValidatorClient.php',
'Sports\Gearman\Worker' => __DIR__ . '/library/Sports/Gearman/Worker.php',
'Sports\Gearman\DropboxWorker' => __DIR__ . '/library/Sports/Gearman/DropboxWorker.php',
'Sports\Gearman\Client' => __DIR__ . '/library/Sports/Gearman/Client.php',
'Sports\Gearman\DropboxClient' => __DIR__ . '/library/Sports/Gearman/DropboxClient.php',
'Sports\Utility\FileReader' => __DIR__ . '/library/Sports/Utility/FileReader.php',
);
main config
// These are various options for the listeners attached to the ModuleManager
'module_listener_options' => array(
// This should be an array of paths in which modules reside.
// If a string key is provided, the listener will consider that a module
// namespace, the value of that key the specific path to that module's
// Module class.
'module_paths' => array(
'./module',
'./vendor',
),
and the controller
namespace SportsUi\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Sports\Database\Model\DropboxMapper;
class DropboxController extends AbstractActionController
{
public function fooAction()
{
// echo "Asdasd";
return array();
}
public function indexAction()
{
// echo "Asdasd";
return array();
}
public function viewFileAction()
{
$dropbox = new DropboxMapper(); //
return array('title'=> 'Title of the page');
}
}

Categories