Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

PHP Starter Application

317 views

Published on

This is a starting point for applications with complex business logic. It is a PHP MVC skeleton with a Domain (Domain Model), Data Mapper and Service Layer. It uses Zend Framework 2 however may be ported to other frameworks quite easily. You are welcome to use it as the foundation for your next application.

Published in: Internet
  • Be the first to comment

  • Be the first to like this

PHP Starter Application

  1. 1. PHP STARTER APPLICATION For Complex Business Logic http://github.com/KimPrince/zf2-starter
  2. 2. Dealing with business complexity General Requirements • Means of organizing logic • Flexible database interaction • A clear API for client code Solution • MVC skeleton with a Model • Model • The Domain, with: • Domain object factories • Collection handling and logic • Proxies • Single-valued properties • Multi-valued properties • Identity map • The Data Mapper • The Service Layer • View – OOTB • Controller – OOTB
  3. 3. The code • Zend Framework 2 • Easily ported to others • Actively maintained • Fork it on github • Two modules • Core • Mapper (implementation) • http://kimprince.com • Detailed usage discussion • Code examples
  4. 4. THE MVC ‘MODEL’ - An umbrella for a whole other structure - The Domain, The Data Mapper, The Service Layer
  5. 5. The Domain: Domain objects • Represent business objects • Typically nouns such as ‘customer’, ‘product’ • Include data and behaviour • Each implements its own interface • Easily proxied or mocked • Abstract parent • Provides common features • Encapsulation • $allowed array • Keys are property names • Boolean values describe required/optional behaviour • $data array stores real values
  6. 6. The Domain: Domain objects (cont) • Construction • Object factories do the heavy lifting • Constructor expects an array of filtered values • Checks that mandatory values have been supplied • Sets any factories and finders which may have been injected • Access • Properties are ‘open for reading, closed for writing’ • __get() – assumes client code can read properties • __set() – assumes client code can NOT write properties • Override these with getPropertyName(), setPropertyName($value) • Identity • Abstract accessors: getId(), setId() • For globally unique id: getShortType($object) . $object->getId() • Value objects are handled differently
  7. 7. The Domain: Object proxies • Most Domain objects have a proxy • Factories may substitute proxies for real properties • A proxy has a real object id and finder (Mapper) • A proxy is realised if/when it is accessed • Unless accessing the id only
  8. 8. The Domain: Collections • One per Domain class (usually) • Each implements own interface • Easily proxied or mocked • Iterable and countable • Commonly returned by Mappers • Contain a factory and an array of raw data • May contain custom logic for the given type • For sorting, filtering, adding members, removing, comparing, … • Pass out a clone when filtering or sorting
  9. 9. The Domain: Collection proxies • Most collections have a proxy • Class diagram (over) • Collections and their proxies inherit from a common hierarchy • Key difference: • A collection becomes an iterator • A collection proxy becomes an iterator aggregate • Iterator aggregate references the real iterator • On construction, proxies receive • A finder – for retrieving the collection • A method name – which exists on the finder • An array of arguments – which are passed to the finder method • Collection proxies are used extensively by factories • As a substitute for multi-valued properties
  10. 10. The Domain: Collection proxies (cont)
  11. 11. The Domain: Object factories • Often long and complex classes • Loaded via an abstract factory • Use the factory method pattern • Factories are service locator aware • Include features related to N+1 selects handling (more later) Method Responsibilities New Object Defaults • Add defaults for new objects • Override inputs where necessary Type Conversion • Cast inputs to required types or proxies Add Relations • Add collection proxies for multi-valued properties Instantiation • Inject to constructor: $data, $finders, $factories
  12. 12. The Domain: Identity map • A safety net • Performance • Model integrity • Main clients: Object factories • Check for existing before instantiating a Domain object • Add newly instantiated Domain objects to the map • Other clients: Data Mappers • Check for existing before executing a ‘find’ query • Add newly created entities to the map • Following a db insert, since that’s when the id is assigned
  13. 13. The Mapper • Translates between object world and the db • Converts between under_score and camelCase • Usually one Mapper class per Domain object • A typical Mapper has: • find($id) – returns a single Domain object • Other single-object finders, such as findByName($name) • Numerous collection finders, such as findByFoo($id) • insert($object) – executes an sql insert • update($object) – executes an sql update • Mappers are loaded via an abstract factory
  14. 14. The Service Layer • Highest layer of the Model • Depends on Domain and Mapper • Service-locator-aware • Composes an event manager • Loaded via an abstract factory • Tasks • “Whatever clients need…” • Persisting changes • Including database transactions
  15. 15. EVERYTHING ELSE Non-Model considerations
  16. 16. Views, controllers, helpers • Views • OOTB • Extensive use of helpers • Forms – Consider hand-crafted for more control • Confidence in performance, based on: • Identity map means no fetching duplicates • Object factories use collection proxies to avoid N+1 selects • Controllers • OOTB • Service locator aware • Helper trait • Inserted into most supertypes • getShortType() identifies a family of objects • TheObject, TheObjectMapper, TheObjectFactory, TheObjectCollection
  17. 17. A note on filtering and validation • May be located in Service Layer or Domain • Option 1: Service Layer • Easy to manage – i.e. audit, fix gaps • Option 2: Domain (and Mapper) • More difficult to manage, but a better fit with OO • Three data contexts: • Newly created entities – filter and validate in the object’s factory • Updates to object properties – filter and validate in custom setters • Finder parameters – filter and validate in Mappers themselves
  18. 18. The N+1 selects problem • Occurs where a Domain object has a multi-valued property • ‘First degree’ problems solved when factory used correctly, e.g.: • If bars is multi-valued property of Foo… • The Foo factory sets Foo->bars to a Bar collection proxy • ‘Second degree’ problems require new factory ‘flavours’ • Flavours are stored in factories as class constants, e.g. FOO::BARS_WITH_BAZ • Use setFlavour() and addFlavour() to configure factory • In flavoured factories, collection proxies eagerly load navigable associations • This affects Mappers too, e.g. Bar Mapper needs findByFooWithBaz($foo) • See detailed usage discussion for more examples
  19. 19. Using the Starter Application • See detailed usage discussion for notes on: • Defining the business problem • Building the Domain • Building the Data Mapper • Building the Service Layer • Building the presentation layer (views, controllers) • Iterating to completion • Also in the usage discussion: • Create your own Starter Application from Zend’s ZF2 Skeleton App.
  20. 20. www.kimprince.com @Kim_Prince

×