2. Magento
About
Zend Certified Engineer
Senior Sw. Engineer @ EPAM
PHP since 2005
CakePHP since 2007
Zend Framework since 2008
Yii since 2010
Symfony 2.0 since 2011
Can also tell you something
about pros & cons of
CodeIgniner, Drupal, Wordpress
5. Magento
Dependency Injection
Only possible with some kind of service locator
Makes able to lazy initialize all resource
dependencies
Simplify debugging and development
Simplify existing components extension and
integration
Dependency injection in PHP 5.3/5.4
http://slidesha.re/vE8Wyp
6. Magento
Service locators in PHP
Most of them require build stage
For performance reasons they
leverage codegeneration
Require dependency configuration in
some of the established ways
Heavily utilize Reflection API
8. Magento
Pimple
73 lines of PHP code
Use closures heavily
Made as fun proof of concept
Good for little projects
Base of Silex microframework
URLS
• Pimple: http://pimple.sensiolabs.org/
• Silex project: http://silex.sensiolabs.org/
9. Magento
Symfony 2 DI Component
Mature production ready
Stores configuration within XML, YAML or annotations
Support for event observers
Support for custom service tagging
Scopes
Require build step for deploy
Supported by Sensio Labs. Paid subscriptions available
Could be integrated through PEAR
Easy
URLS go here:
• DI for PHP 5.2 - http://bit.ly/uGt8CK
• PEAR channel: http://pear.symfony.com/
• Service Container - http://bit.ly/s7F8HF
10. Magento
Some cookies: CLI
Some tasks could be
done through CLI easier
Cron?
Daemons?
Continuous integration?
Expose services to
console?
11. Magento
cli:call
What about writing
custom command for
accessing nearly
every defined service
in container for
isolated working?
$ ./app/console cli:call
service.name methodName
[arg1, arg2, arg3, …]
12. Magento
Metaprogramming
Is how programs are self-aware
Is not recommended to use at run time
Is the art of operating metadata
Is black magic processed at build step
Is possible with PHP 5
Is making the code shorter
16. Magento
Reflection API
A way of retrieving information about
parameters for a class method
A way of accessing private property of a
parent class
A way of passing method parameters by name
Another way of making callback
Other more or less interesting ways of
application
17. Magento
Annotation magic
Actually are custom docblock tags with some extend
Some kind of XDoclet API for PHP
Some other couple of words here
Some frameworks endorse usage: Symfony2 & FLOW3
Couple of existing solutions available
• Regular expressions
• PHPUnit
• ZendReflectionDocblockTag (just extended PCRE, actually)
• Doctrine annotation reader (parser-based method)
Links:
• Doctrine Annotations Reference http://bit.ly/s6kQfh
• An article of 2008 http://bit.ly/uT1v2U
• XDoclet overview of 2005 http://bit.ly/tYy8pa
18. Magento
Tokenization
Just token_get_all() and
be insane
Build a classmap file with
namespace information
Generate unit test
skeletons
Put all TODO’s in
comments as tickets to
Jira
Some of more
sophisticated things I
haven’t thought about
20. Magento
SQL: Sharding. Annotations?..
Get meta-info about sharded connection to
use from query directly
Or parse the query, but little longer
/*entity customer://1234 */
SELECT name FROM customer WHERE
id = 1234
Database Scale http://slidesha.re/vC1i9x
Sharding for startups http://bit.ly/vLa68N
21. Magento
Doctrine Common: Annotation reader
Annotation is a class
Any number of properties could be passed to
constructor
Nesting
Short forms
Takes time to process
22. Magento
Takes time to process?
All configuration is read from DI container
DI container is regenerated upon build
Dev. env. regenerates DI each request
Prod. env. reads cached DI
Annotations aren’t processed in prod. env.
PROFIT!
23. Magento
… well, mostly…
Not all is processed on build
Annotations are good for event
listeners *
Convenient way for storing meta-
information within the code
* Classes defined as services and tagged with special event hooks. Later
transformed to code in some of generated DIC methods.
24. Magento
Processing annotations
1. Create class implementing
SymfonyComponentDependencyInjectionCompiler
CompilerPassInterface
2. Collect annotations via reader
3. Save processed metadata in container via
ContainerBuilder::setParameter()
4. Add build(ContainerBuilder $cb) method to bundle
main class
5. Add kernel.* event observers
6. PROFIT
26. Magento
Autowiring
Inject serviced needed to places needed
Reflection-heavy
Hard, but possible for PHP
MVC simplifying
Ready solutions
• Autowiring Bundle – http://bit.ly/uDTKYi
• JMSDiExtraBundle – http://bit.ly/t7pP89
• FLOW3 autowiring – http://bit.ly/tcJQ10
27. Magento
Common now is less: CRON
• Adding periodical tasks seem somewhat boring
• With annotated configuration it could be set up in
seconds
• This simple annotation will be transformed in
crontab file to something like
0 */4 * * * /usr/bin/php /path/to/app/console cli:call
our.user.service sendNotifications
29. Magento
Doing things wrong
When my IDE* cannot help
auto completing I'm using
bad practice programming
* Netbeans, Eclipse, PHPStorm, .. put your favorite here
30. Magento
Real life: Autowiring
Create services with
simple annotating
them
Inject existing services
to class properties
Apply name guessing
strategies
JMSDiExtraBundle
used
31. Magento
Keeping code short
Configure routes
inline
Configure templates
inline
Inject only services,
that the action really
needs. Recognized by
IDE directly
Return needed variables for view
32. Magento
grep
Nice tool to get only those classes
with annotations & autowiring to
parse
True UNIX way
Or use a class-map file – URL goes
here
Done at the build step
33. Magento
Codegeneration and codedegeneration
Programs program programs
As ideal – lets developer develop business logic, not the
boilerplate
Programs make pieces of programs
• RAD tools and frameworks
• IDE code templates
Having templates is really good
Customization is good
“Code Generation in Action” by Jack Herrington D.
http://amzn.to/skQzEr
34. Magento
Use cases
Project rapid start
Enterprise stuff
DB interaction & ORM
Better unit test skeletons
Performance
Code transformation
Boilerplates & customization
Bunch of routine stuff …
35. Magento
Use-case: Generating unit-tests
Goal: save time creating boilerplate code
for
• Initialization of all dependent objects
• Public methods
• Possible conditional logic
• Asserting actual and expected results
• Mock object methods boilerplate
37. Magento
Use-case: proxy generation for performance
Template engines – compile own markup to PHP
Symfony DI Component – generates service bootstrap
in PHP
JMSSecurityBundle – puts security checking to
generated proxies
SymfonyGeneratorBundle – makes writing boilerplate
CRUD code for controllers and entities faster and
easier.
Put your own here.
38. Magento
Common things
Framework specific
Define placeholders
Extend and Proxy
Liscov substitution principle
Have templates, that are editable
Have an easy way to make own templates
Regenerate stuff on architecture change
40. Magento
Generating codegenerators
Have an ideal code sample: R&D
something nice
Get code slice from line X to line Y
Define common pattern fast
Get template. Test it. Improve
sample.
Apply results of your concept fast
41. Magento
In 6 months …
Improve ideal code sample
Improve template
Regenerate those hundreds of files
in seconds with compatibility kept
PROFIT.
42. Magento
A tool
Some internal tool for generating generators, unit tests, fixtures
Typical usage:
Sample file Start and end lines
Format
$ pugooroo tpl RolseService.php 108 118
Copy output
--pieces --heredoc --copy
Pick vars to buffer
--function generateStuff
cogen> Enter code pieces you want to replace Wrap up to
function
user
Interactive
group
CLI app!11
Group
cogen> Enter alias for 'user' [piece0]: FIRST
cogen> Enter alias for 'group' [piece1]: SECOND
cogen> Enter alias for 'Group' [piece2]: SECOND_CAMELCASED
43. Magento
And typical result
function generateStuff ($FIRST, $SECOND, $SECOND_CAMELCASED) {
$tmpl = <<<EOF
${$FIRST}Counts = array();
while ($row = $stmt->fetchObject()) {
${$FIRST}Counts[(int) $row->{$SECOND}_id] = (int) $row-
>num_{$FIRST}s;
}
foreach(${$SECOND}s as ${$SECOND}) {
/* @var ${$SECOND} {$SECOND_CAMELCASED} */
if(isset (${$FIRST}Counts[${$SECOND}->getId()])) {
${$SECOND}->setUsercount(${$FIRST}Counts[${$SECOND}->getId()]);
}
}
EOF;
return $tmpl;
}
45. Magento
The more sophisticated things
#Joined array turns out to be more flexible than HEREDOC:
function generateStuff ($FIRST, $SECOND, $SECOND_CAMELCASED, $needsSomething =
true) {
$tmpl = array();
$tmpl[] = " ${$FIRST}Counts = array();";
$tmpl[] = " while ($row = $stmt->fetchObject()) {";
$tmpl[] = " ${$FIRST}Counts[(int) $row->{$SECOND}_id] = (int) $row-
>num_{$FIRST}s;";
$tmpl[] = " }";
$tmpl[] = " ";
if($needsSomething) {
$tmpl[] = " foreach(${$SECOND}s as ${$SECOND}) {";
$tmpl[] = " if(isset (${$FIRST}Counts[${$SECOND}-
>getId()])) {";
$tmpl[] = " ${$SECOND}-
>setUsercount(${$FIRST}Counts[${$SECOND}->getId()]);";
$tmpl[] = " }";
$tmpl[] = " }";
$tmpl[] = "";
}
$tmpl = join("n", $tmpl);
return $tmpl;
}
46. Magento
Real life: tagged keys in cache
Goal:
• Resultset of a method could be cached
• Resultset is dependent on other resultsets validity
• If dependent resultset becomes invalid – invalidate only
needed keys
• Perform application-wide substitutions like currently logged in
user and etc
• Make adding and removing cache really easy
Bad things
• Require complex code to maintain
• Hard to read
47. Magento
Solution
Java EhCache framework – http://ehcache.org/
@Cacheable & @TriggersRemove with tagging-
specific features
Generate code for proxy class
Substitute original class within inversion of
control container
Call the same method without any API change
Turn off caching when needed