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.
Related
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.
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
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.
I come from a Codeigniter background. At the moment I am building a CMS in Laravel.
What I would like to know is how can I separate the backend and frontend in Laravel?
In Codeigniter i use to make two controller Admin_Controller and Front_Controller.
Article extends Admin_Controller
Article extends Front_Controller
and the file structure looked like this
controller
--admin
---user
---blog
---news
--user
--blog
--news
for admin controller I make separate folder and front end controller remain in root of controller folder.
Should I use the same logic in Laravel or is there a better way to do it?
If you want to create thinks like Taylor Otwell and 'the core' is trying to teach people do things in Laravel, this is a good start:
Your files could be organized as
├── app
│ ├── ZIP
│ │ ├── Controllers
│ │ │ ├── Admin
│ │ │ │ ├── Base.php <--- your base controller
│ │ │ │ ├── User.php
│ │ │ │ ├── Blog.php
│ │ │ │ ├── News.php
│ │ │ ├── Front
│ │ │ │ ├── Base.php <--- your base controller
│ │ │ │ ├── User.php
│ │ │ │ ├── Blog.php
│ │ │ │ ├── News.php
Configure a PSR-0 or PSR-4 (better) to autoload your classes:
"psr-0": {
"ZIP": "app/"
},
Create namespaces to all tour classes, according to your source tree:
<?php namespace ZIP\Controllers\Admin
class User extends Base {
}
<?php namespace ZIP\Controllers\Front
class Blog extends Base {
}
And create your base controllers
<?php namespace ZIP\Controllers\Admin
use Controller;
class Base extends Controller {
}
You can certainly do it the two controllers way or if you like even more separation (and a more 'laravel' way), write your front end and backend as separate packages (previously called bundles in Laravel 3).
They basically behave like standalone applications within your main app. They can have their own routes, models, controllers etc. You can also write 'core code' at the main application level which can be shared across the packages.
If you are moving to Laravel as you want to learn a new framework, then you should definitely try and get a handle on packages - very powerful.
If you are being 'made' to move to Laravel, or have some time pressure, just do it as you have normally done. Laravel is flexible and will be fine either way you do it.
For more info, see the docs.
Laravel current version (4 at time of writing) - http://laravel.com/docs/packages
Laravel 3 - http://three.laravel.com/docs/bundles
I'm quite new to both Zend and QUnit and I've got a bit stuck when it comes to setting up my QUnit tests to test my JavaScript.
I'm trying to test to some DOM manipulation and I understand that I have to put the html I'm testing against inside a #qunit-fixture div in my Qunit test file. However I've got a partial view helper used in my main Zend application (works fine in my view scripts) which I just want to echo out rather than having to rewrite the html used in the helper itself (to avoid duplication). The JavaScript I am attempting to test is used in the partial view helper hence wanting to use it.
Here's the folder structure for my application with just the important files and a few others remaining:
├── application
│ ├── Bootstrap.php
│ ├── configs
│ ├── controllers
│ ├── layouts
│ │ └── scripts
│ ├── models
│ ├── plugins
│ └── views
│ ├── helpers
│ └── scripts
│ ├── error
│ ├── index
│ └── partials
│ └── partialViewHelperIWantToUse.phtml
├── docs
├── features
├── Gemfile
├── Gemfile.lock
├── js-tests
│ ├── qunitTestFile.html
│ └── vendor
│ └── qunit
│ ├── qunit.css
│ └── qunit.js
├── library
│ ├── Custom
├── public
│ ├── css
│ ├── img
│ ├── index.php
│ └── js
│ ├── jquery
│ │ └── jquery-1.7.2.min.js
│ └── javaScriptIWantToTest.js
├── Rakefile
├── tasks
└── tests
├── application
│ ├── controllers
│ └── models
├── bootstrap.php
├── library
│ └── Custom
└── phpunit.xml
I want to do something like this in my qunitTestFile.html (found in js-tests)
<div id="qunit-fixture">
<?php echo $view->partial('partialViewHelperIWantToUse.phtml') ?>
</div>
but it currently doesn't work. Renaming the qunitTestFile to have a .phtml extension causes nothing to echo out but the error "call to a member function partial() on a non-object" appears in the apache error log (I expected that but it was a simple thing to try!). I have a hunch that I might need to create another bootstrap file or something but both and Zend and Qunit are new to me so I'm a bit lost. =)
I hope that's clear and I've given enough information but let me know if it isn't.
Thanks!
Since I do not exactly know which Zend version you use, I am not sure if this helps you:
The partial()-Function is a helper of your view. Since a View .phtml File is called in a Zend_View-Context (if you use an Controller-Action to show the View) you should use
$this->partial('...');
You can setup a Zend_View for yourself, but according your directory structure, I assume you use an MVC-Pattern.