SlideShare une entreprise Scribd logo
1  sur  136
Télécharger pour lire hors ligne
Error Reporting
in Zend Framework 2

Zend Framework Day – Turin, Italy – 07/02/2014
STEVE MARASPIN
@maraspin
http://www.mvlabs.it/
http://friuli.grusp.org/

5
WHY WORRY?
WE SCREW UP
WE ALL SCREW UP
Application Failures
Application Failures
User Mistakes
INCREASED SUPPORT COST
ABANDONMENT
THE BOTTOM LINE
User Input = Mistake Source
Validation Handling
User Privacy Concerns
• Over 40% of online shoppers are very
concerned over the use of personal
information
• Public opinion polls have revealed a
general desire among Internet users to
protect their privacy
Online Privacy: A Growing Threat. - Business Week, March 20, 2000, 96. Internet Privacy in ECommerce:
Framework, Review, and Opportunities for Future Research - Proceedings of the 41st Hawaii
International Conference on System Sciences - 2008
Validation Handling
Improved Error Message
+70% CONVERSIONS
21
Creating A Form in ZF2
<?php
namespace ApplicationForm;
use ZendFormForm;
class ContactForm extends Form
{
public function __construct() {
parent::__construct();
// ...
}
//...
}
Creating A Form in ZF2
<?php
namespace ApplicationForm;
use ZendFormForm;
class ContactForm extends Form
{
public function __construct() {
parent::__construct();
// ...
}
//...
}
Adding Form Fields
public function init() {
$this->setName('contact');
$this->setAttribute('method', 'post');
[…]..
$this->add(array('name' => 'email',
'type' => 'text',
'options' => array(
'label' => 'Name',
),
);
$this->add(array('name' => 'message',
'type' => 'textarea',
'options' => array(
'label' => 'Message',
),
);
//. […]..
}
Adding Form Fields
public function init() {
$this->setName('contact');
$this->setAttribute('method', 'post');
[…]..
$this->add(array('name' => 'email',
'type' => 'text',
'options' => array(
'label' => 'Name',
),
);
$this->add(array('name' => 'message',
'type' => 'textarea',
'options' => array(
'label' => 'Message',
),
);
//. […]..
}
VALIDATION
Form Validation: InputFilter
Validation: inputFilter
<?php
namespace ApplicationForm;
[…]
class ContactFilter extends InputFilter

{
public function __construct() {

// filters go here
}

}
Validation: inputFilter
<?php
namespace ApplicationForm;
[…]
class ContactFilter extends InputFilter

{
public function __construct() {

// filters go here
}

}
Required Field Validation
$this->add(array(
'name' => 'email',
'required' => true,
'filters' => array(
array(
'name' => 'StringTrim'),
),
'validators' => array(
array(
'name' => 'EmailAddress',
)
)
));
Required Field Validation
$this->add(array(
'name' => 'email',
'required' => true,
'filters' => array(
array(
'name' => 'StringTrim'),
),
'validators' => array(
array(
'name' => 'EmailAddress',
)
)
));
InputFilter Usage
<?php
namespace ApplicationController;

[…]
class IndexController extends AbstractActionController
{

public function contactAction()
{
$form = new Contact();
$filter = new ContactFilter();

$form->setInputFilter($filter);
return new ViewModel(array(
'form' => $form );

}
}
InputFilter Usage
<?php
namespace ApplicationController;

[…]
class IndexController extends AbstractActionController
{

public function contactAction()
{
$form = new Contact();
$filter = new ContactFilter();

$form->setInputFilter($filter);
return new ViewModel(array(
'form' => $form );

}
}
Standard Error Message
Improved Error Message
Error Message Customization
$this->add(array(
'name' => 'email',

'required' => true,
'filters' => array(
array('name' => 'StringTrim'),
),
'validators' => array(

array('name' =>'NotEmpty',
'options' => array(
'messages' => array(
NotEmpty::IS_EMPTY => 'We need an '.
'e-mail address to be able to get back to you'
),
),
),
array('name' => 'EmailAddress'),

)
));
Error Message Customization
$this->add(array(
'name' => 'email',

'required' => true,
'filters' => array(
array('name' => 'StringTrim'),
),
'validators' => array(

array('name' =>'NotEmpty',
'options' => array(
'messages' => array(
NotEmpty::IS_EMPTY => 'We need an '.
'e-mail address to be able to get back to you'
),
),
),
array('name' => 'EmailAddress'),

)
));
More than we need…
Check Chain
$this->add(array(
'name' => 'email',

'required' => true,
'filters' => array(
array('name' => 'StringTrim'),
),
'validators' => array(

array('name' =>'NotEmpty',
'options' => array(
'messages' => array(
NotEmpty::IS_EMPTY => 'We need an '.
'e-mail address to be able to get back to you'
),
),
'break_chain_on_failure' => true,
),

array('name' => 'EmailAddress'),
) ));
Ok, good…
…but, what if?
Words to Avoid

http://uxmovement.com/forms/how-to-make-your-form-error-messages-more-reassuring/
A few tips:
•

•

•

45

Provide the user with a solution to the
problem
Do not use technical jargon, use
terminology that your audience
understands
Avoid uppercase text and exclamation
points
Improved message
Condensing N messages into 1
$this->add(array(
'name' => 'email',

'required' => true,
'validators' => array(
array('name' =>'NotEmpty',
'options' => array(
'messages' => array(

NotEmpty::IS_EMPTY => 'We need an '.
'e-mail address to be able to get back to you'
)),
'break_chain_on_failure' => true,
),
array('name' => 'EmailAddress',
'options' => array(
'message' => 'E-Mail address does not seem to be valid.
Please make sure it contains the @ symbol

and a valid domain name.',
)));
Condensing N messages into 1
$this->add(array(
'name' => 'email',

'required' => true,
'validators' => array(
array('name' =>'NotEmpty',
'options' => array(
'messages' => array(

NotEmpty::IS_EMPTY => 'We need an '.
'e-mail address to be able to get back to you'
)),
'break_chain_on_failure' => true,
),
array('name' => 'EmailAddress',
'options' => array(
'message' => 'E-Mail address does not seem to be valid.
Please make sure it contains the @ symbol

and a valid domain name.',
)));
Messages VS message
$this->add(array(
'name' => 'email',

'required' => true,
'validators' => array(
array('name' =>'NotEmpty',
'options' => array(
'messages' => array(

NotEmpty::IS_EMPTY => 'We need an '.
'e-mail address to be able to get back to you'
)),
'break_chain_on_failure' => true,
),
array('name' => 'EmailAddress',
'options' => array(
'message' => 'E-Mail address does not seem to be valid.
Please make sure it contains the @ symbol

and a valid domain name.',
)));
Translated Error Messages
Default Message Translation
public function onBootstrap(MvcEvent $e)
{
$translator = $e->getApplication()
->getServiceManager()->get('translator');

$translator->addTranslationFile(
'phpArray', __DIR__ .
'/../../vendor/zendframework/zendframework/'.
'resources/languages/it/Zend_Validate.php',
'default',
'it_IT'
);
AbstractValidator::setDefaultTranslator($translator);
}
Custom Message Translation
$this->add(array(
'name' => 'email',
'required' => true,
'validators' => array(
array('name' =>'NotEmpty',
'options' => array(
'translator' => $translator,
'message' => $translator->translate(
'Make sure your e-mail address contains the @
symbol and a valid domain name.'
)),
'break_chain_on_failure' => true,
),
)));
Form Factory
$translator = $I_services->get('translator');
$I_form = new Contact();
$I_filter = new ContactFilter($translator);
$I_form->setInputFilter($I_filter);
return $I_form;
Translated Error Message
http://patterntap.com/pattern/funny-and-helpful-404-error-page-mintcom
56
Error Display Configuration
Skeleton Applicaton
Configuration
Hiding Exception Traces
'view_manager' => array(

'display_not_found_reason' => false,
'display_exceptions' => false,
'doctype' => 'HTML5',
'not_found_template' => 'error/404',
'exception_template' => 'error/index',
'template_map' => array(
'layout/layout' => __DIR__ . '/../view/layout/layout.phtml',
'application/index/index'=> __DIR__ .
'/../view/application/index/index.phtml',
'error/404' => __DIR__ . '/../view/error/404.phtml',
'error/index' => __DIR__ . '/../view/error/index.phtml',
),
'template_path_stack' => array(
__DIR__ . '/../view',
),
),
Hiding Exception Traces
'view_manager' => array(

'display_not_found_reason' => false,
'display_exceptions' => false,
'doctype' => 'HTML5',
'not_found_template' => 'error/404',
'exception_template' => 'error/index',
'template_map' => array(
'layout/layout' => __DIR__ . '/../view/layout/layout.phtml',
'application/index/index'=> __DIR__ .
'/../view/application/index/index.phtml',
'error/404' => __DIR__ . '/../view/error/404.phtml',
'error/index' => __DIR__ . '/../view/error/index.phtml',
),
'template_path_stack' => array(
__DIR__ . '/../view',
),
),
Custom Error Pages
'view_manager' => array(

'display_not_found_reason' => false,
'display_exceptions' => false,
'doctype' => 'HTML5',
'not_found_template' => 'error/404',
'exception_template' => 'error/index',
'template_map' => array(
'layout/layout' => __DIR__ . '/../view/layout/layout.phtml',
'application/index/index'=> __DIR__ .
'/../view/application/index/index.phtml',
'error/404' => __DIR__ . '/../view/error/404.phtml',
'error/index' => __DIR__ . '/../view/error/index.phtml',
),
'template_path_stack' => array(
__DIR__ . '/../view',
),
),
How about PHP Errors?
class IndexController extends AbstractActionController
{
public function indexAction()
{

1/0;
return new ViewModel();
}
}
How about PHP Errors?
class IndexController extends AbstractActionController
{
public function indexAction()
{

1/0;
return new ViewModel();
}
}
Early error detection principle
What can we do?
Handling PHP Errors
public function onBootstrap(MvcEvent $I_e) {
[…]
set_error_handler(array('ApplicationModule','handlePhpErrors'));
}
public static function handlePhpErrors($i_type,
$s_message,
$s_file,
$i_line) {
if (!($i_type & error_reporting())) { return };

throw new Exception("Error: " . $s_message . " in file " . $s_file
. " at line " . $i_line);
}
What happens now?
class IndexController extends AbstractActionController
{
public function indexAction()
{

1/0;
return new ViewModel();
}
}
Now… what if?
class IndexController extends AbstractActionController
{
public function indexAction()
{
$doesNotExist->doSomething();
return new ViewModel();
}
}
Fatal error: Call to a member function doSomething() on a non-object in
/srv/apps/zfday/module/Application/src/Application/Controller/IndexController.php
on line 20
FATAL ERRORS
Fatal Error Handling
public function onBootstrap(MvcEvent $I_e) {
[…]
$am_config = $I_application->getConfig();
$am_environmentConf = $am_config['mvlabs_environment'];
// Fatal Error Recovery
if (array_key_exists('recover_from_fatal', $am_environmentConf) &&
$am_environmentConf['recover_from_fatal']) {
$s_redirectUrl = $am_environmentConf['redirect_url'];
}
$s_callback = null;
if (array_key_exists('fatal_errors_callback', $am_environmentConf)) {
$s_callback = $am_environmentConf['fatal_errors_callback'];
}
register_shutdown_function(array('ApplicationModule',
'handleFatalPhpErrors'),
$s_redirectUrl,
$s_callback);
}
Fatal Error Handling
/**
* Redirects user to nice page after fatal has occurred
*/
public static function handleFatalPhpErrors($s_redirectUrl,
$s_callback = null) {
if (php_sapi_name() != 'cli' && @is_Array($e = @get_last())) {
if (null != $s_callback) {
// This is the most stuff we can get.
// New context outside of framework scope
$m_code = isset($e['type']) ? $e['type'] : 0;
$s_msg = isset($e['message']) ? $e['message']:'';
$s_file = isset($e['file']) ? $e['file'] : '';
$i_line = isset($e['line']) ? $e['line'] : '';
$s_callback($s_msg, $s_file, $i_line);
}
header("location: ". $s_redirectUrl);
}
return false;
}
Fatal Error Handling
'mvlabs_environment' => array(
'exceptions_from_errors' => true,
'recover_from_fatal' => true,
'fatal_errors_callback' => function($s_msg, $s_file, $s_line) {
return false;
},
'redirect_url' => '/error',

'php_settings' => array(
'error_reporting' => E_ALL,
'display_errors' => 'Off',
'display_startup_errors' => 'Off',
),
),
PHP Settings Conf
'mvlabs_environment' => array(
'exceptions_from_errors' => true,
'recover_from_fatal' => true,
'fatal_errors_callback' => function($s_msg, $s_file, $s_line) {
return false;
},
'redirect_url' => '/error',

'php_settings' => array(
'error_reporting' => E_ALL,
'display_errors' => 'Off',
'display_startup_errors' => 'Off',
),
),
PHP Settings
public function onBootstrap(MvcEvent $I_e) {
[…]
foreach($am_phpSettings as $key => $value) {
ini_set($key, $value);
}
}
NICE PAGE!
CUSTOMER SUPPORT TEAM REACTION
http://www.flickr.com/photos/18548283@N00/8030280738
ENVIRONMENT
DEPENDANT
CONFIGURATION
During Deployment
Local/Global Configuration Files
During Deployment
Runtime
Index.php
// Application wide configuration
$am_conf = $am_originalConf = require 'config/application.config.php';

// Environment specific configuration
$s_environmentConfFile = 'config/application.'.$s_env.'.config.php';
if (file_exists($s_environmentConfFile) &&
is_readable($s_environmentConfFile)) {
// Specific environment configuration merge
$am_environmentConf = require $s_environmentConfFile;
$am_conf = ZendStdlibArrayUtils::merge($am_originalConf,
$am_environmentConf
);
}

// Additional Specific configuration files are also taken into account
$am_conf["module_listener_options"]["config_glob_paths"][] =
'config/autoload/{,*.}' . $s_env . '.php';
ZendMvcApplication::init($am_conf)->run();
application.config.php
'modules' => array(
'Application',
),
Application.dev.config.php
'modules' => array(
'Application',
'ZendDeveloperTools',
),
Enabling Environment Confs
// Application nominal environment
$am_conf = $am_originalConf = require 'config/application.config.php';

// Environment specific configuration
$s_environmentConfFile = 'config/application.'.$s_env.'.config.php';
// Do we have a specific configuration file?
if (file_exists($s_environmentConfFile) &&
is_readable($s_environmentConfFile)) {
// Specific environment configuration merge
$am_environmentConf = require $s_environmentConfFile;
$am_conf = ZendStdlibArrayUtils::merge($am_originalConf,
$am_environmentConf );
}

// Additional Specific configuration files are also taken into account
$am_conf["module_listener_options"]["config_glob_paths"][] =
'config/autoload/{,*.}' . $s_env . '.php';
ZendMvcApplication::init($am_conf)->run();
Env Dependant Conf Files
index.php Check
// What environment are we in?
$s_env = getenv('APPLICATION_ENV');
if (empty($s_env)) {
throw new Exception('Environment not set.'.
' Cannot continue. Too risky!');
}
Apache Config File
<VirtualHost *:80>
DocumentRoot /srv/apps/zfday/public
ServerName www.dev.zfday.it
SetEnv APPLICATION_ENV "dev"
<Directory /srv/apps/zfday/public>
AllowOverride FileInfo
</Directory>
</VirtualHost>
LOGGING

http://www.flickr.com/photos/otterlove/8154505388/
Why Log?

Troubleshooting
• Stats Generation
• Compliance
•

95
Zend Log
$logger = new ZendLogLogger;
$writer = new ZendLogWriterStream('/var/log/app.log');
$logger->addWriter($writer);
$logger->info('Informational message');
$logger->log(ZendLogLogger::EMERG, 'Emergency message');
Zend Log
$logger = new ZendLogLogger;
$writer = new ZendLogWriterStream('/var/log/app.log');
$logger->addWriter($writer);
$logger->info('Informational message');
$logger->log(ZendLogLogger::EMERG, 'Emergency message');
ZendLogLogger::registerErrorHandler($logger);
ZendLogLogger::registerExceptionHandler($logger);
Writers

98
Writers

99
Logrotate
/var/log/app.log {
missingok
rotate 7
daily
notifempty
copytruncate
compress
endscript
}
100
Writers

101
Writers

102
Writers

103
Zend Log Ecosystem

104
Filter Example
$logger = new ZendLogLogger;
$writer1 = new ZendLogWriterStream('/var/log/app.log');
$logger->addWriter($writer1);
$writer2 = new ZendLogWriterStream('/var/log/err.log');
$logger->addWriter($writer2);
$filter = new ZendLogFilterPriority(Logger::CRIT);
$writer2->addFilter($filter);
$logger->info('Informational message');
$logger->log(ZendLogLogger::CRIT, 'Emergency message');
Monolog
use MonologLogger;
use MonologHandlerStreamHandler;
$log = new Logger('name');
$log->pushHandler(new StreamHandler('/var/log/app.log',
Logger::WARNING));
$log->addWarning('Foo');
$log->addError('Bar');
Monolog Components

107
How to log?
class IndexController {

public function helloAction() {
return new ViewModel('msg' =>"Hello!");

}
}
Traditional Invokation
Logging Within Controller
class GreetingsController {
public function helloAction() {
$I_logger = new Logger();
$I_logger->log("We just said Hello!");
return new ViewModel('msg' =>"Hello!");
}
}
Single Responsability Violation
class GreetingsController {
public function helloAction() {
$I_logger = new Logger();
$I_logger->log("We just said Hello!");
return new ViewModel('msg' =>"Hello!");
}
}
Fat Controllers
class GreetingsController {

public function helloAction() {
$I_logger = new Logger();
$I_logger->log("We just said Hello!");
$I_mailer = new Mailer();
$I_mailer->mail($s_msg);
$I_queue = new Queue();
$I_queue->add($s_msg);
return new ViewModel('msg' =>"Hello!");
}
}
CROSS CUTTING CONCERNS
What can we do?
Handling Events
class Module {
public function onBootstrap(MvcEvent $e) {
$eventManager = $e->getApplication()
->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach($eventManager);
$logger = $sm->get('logger');
$eventManager->attach('wesaidHello',
function(MvcEvent $event) use
($logger) {
$logger->log($event->getMessage());
);
}
}
Triggering An Event
class GreetingsController {

public function helloAction() {
$this->eventManager
->trigger('wesaidHello',
$this,
array('greeting' => 'Hello!')
);
return new ViewModel('msg' => "Hello!");
}
}
Traditional Invokation
Event Manager
OBSERVER
http://www.flickr.com/photos/lstcaress/502606063/
Event Manager
Handling Framework Errors
class Module {
public function onBootstrap(MvcEvent $e) {
$eventManager = $e->getApplication()
->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach($eventManager);

$logger = $sm->get('logger');
$eventManager->attach(MvcEvent::EVENT_RENDER_ERROR,
function(MvcEvent $e) use ($logger) {
$logger->info('An exception has Happened ' .
$e->getResult()->exception->getMessage());
}, -200);
);
}
}
Event Manager
Stuff to take home
1.
2.
3.

123

When reporting errors, make sure to be
nice with users
Different error reporting strategies could
be useful for different environments
The event manager reduces coupling and
provides flexibility
2 min intro
https://xkcd.com/208/
Starting Things Up
input { stdin { } }
output { stdout { codec => rubydebug } }
Starting Things Up
input { stdin { } }
output { stdout { codec => rubydebug } }
java -jar logstash-1.3.3-flatjar.jar agent -f sample.conf
Integrated Elasticsearch
input {

file { path => ["/opt/logstash/example.log"] }
}
output {
stdout { codec => rubydebug }
elasticsearch { embedded => true }
}
java -jar logstash-1.3.3-flatjar.jar agent -f elastic.conf
Integrated Web Interface
input {

file { path => ["/opt/logstash/example.log"] }
}
output {
stdout { codec => rubydebug }
elasticsearch { embedded => true }
}
java -jar logstash.jar agent -f elastic.conf --web
Kibana
Thank you for your attention

Stefano Maraspin
@maraspin
@maraspin
Stefano Maraspin
@maraspin

Contenu connexe

Tendances

Php Security By Mugdha And Anish
Php Security By Mugdha And AnishPhp Security By Mugdha And Anish
Php Security By Mugdha And AnishOSSCube
 
Zend Framework 1.9 Setup & Using Zend_Tool
Zend Framework 1.9 Setup & Using Zend_ToolZend Framework 1.9 Setup & Using Zend_Tool
Zend Framework 1.9 Setup & Using Zend_ToolGordon Forsythe
 
PHPunit and you
PHPunit and youPHPunit and you
PHPunit and youmarkstory
 
PHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the testsPHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the testsMichelangelo van Dam
 
Concern of Web Application Security
Concern of Web Application SecurityConcern of Web Application Security
Concern of Web Application SecurityMahmud Ahsan
 
Dealing with Legacy PHP Applications
Dealing with Legacy PHP ApplicationsDealing with Legacy PHP Applications
Dealing with Legacy PHP ApplicationsClinton Dreisbach
 
Proposed PHP function: is_literal()
Proposed PHP function: is_literal()Proposed PHP function: is_literal()
Proposed PHP function: is_literal()Craig Francis
 
SCULPT! YOUR! TESTS!
SCULPT! YOUR! TESTS!SCULPT! YOUR! TESTS!
SCULPT! YOUR! TESTS!Taras Oleksyn
 
Open Source Search: An Analysis
Open Source Search: An AnalysisOpen Source Search: An Analysis
Open Source Search: An AnalysisJustin Finkelstein
 
Php Security3895
Php Security3895Php Security3895
Php Security3895Aung Khant
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxMichelangelo van Dam
 
Jquery presentation
Jquery presentationJquery presentation
Jquery presentationguest5d87aa6
 

Tendances (19)

Php Security By Mugdha And Anish
Php Security By Mugdha And AnishPhp Security By Mugdha And Anish
Php Security By Mugdha And Anish
 
Zend Framework 1.9 Setup & Using Zend_Tool
Zend Framework 1.9 Setup & Using Zend_ToolZend Framework 1.9 Setup & Using Zend_Tool
Zend Framework 1.9 Setup & Using Zend_Tool
 
PHPunit and you
PHPunit and youPHPunit and you
PHPunit and you
 
PHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the testsPHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the tests
 
Php Security
Php SecurityPhp Security
Php Security
 
PHPSpec BDD for PHP
PHPSpec BDD for PHPPHPSpec BDD for PHP
PHPSpec BDD for PHP
 
Unit testing zend framework apps
Unit testing zend framework appsUnit testing zend framework apps
Unit testing zend framework apps
 
Concern of Web Application Security
Concern of Web Application SecurityConcern of Web Application Security
Concern of Web Application Security
 
Dealing with Legacy PHP Applications
Dealing with Legacy PHP ApplicationsDealing with Legacy PHP Applications
Dealing with Legacy PHP Applications
 
PHP Security
PHP SecurityPHP Security
PHP Security
 
Extend sdk
Extend sdkExtend sdk
Extend sdk
 
Proposed PHP function: is_literal()
Proposed PHP function: is_literal()Proposed PHP function: is_literal()
Proposed PHP function: is_literal()
 
SCULPT! YOUR! TESTS!
SCULPT! YOUR! TESTS!SCULPT! YOUR! TESTS!
SCULPT! YOUR! TESTS!
 
Seam Glassfish Slidecast
Seam Glassfish SlidecastSeam Glassfish Slidecast
Seam Glassfish Slidecast
 
Building web APIs in PHP with Zend Expressive
Building web APIs in PHP with Zend ExpressiveBuilding web APIs in PHP with Zend Expressive
Building web APIs in PHP with Zend Expressive
 
Open Source Search: An Analysis
Open Source Search: An AnalysisOpen Source Search: An Analysis
Open Source Search: An Analysis
 
Php Security3895
Php Security3895Php Security3895
Php Security3895
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBenelux
 
Jquery presentation
Jquery presentationJquery presentation
Jquery presentation
 

En vedette

ZF2 Modular Architecture - Taking advantage of it
ZF2 Modular Architecture - Taking advantage of itZF2 Modular Architecture - Taking advantage of it
ZF2 Modular Architecture - Taking advantage of itSteve Maraspin
 
Moduli su Zend Framework 2: come sfruttarli
Moduli su Zend Framework 2: come sfruttarliModuli su Zend Framework 2: come sfruttarli
Moduli su Zend Framework 2: come sfruttarliStefano Valle
 
Elegant Ways of Handling PHP Errors and Exceptions
Elegant Ways of Handling PHP Errors and ExceptionsElegant Ways of Handling PHP Errors and Exceptions
Elegant Ways of Handling PHP Errors and ExceptionsZendCon
 
Asset management with Zend Framework 2
Asset management with Zend Framework 2Asset management with Zend Framework 2
Asset management with Zend Framework 2Stefano Valle
 
Instant ACLs with Zend Framework 2
Instant ACLs with Zend Framework 2Instant ACLs with Zend Framework 2
Instant ACLs with Zend Framework 2Stefano Valle
 
Unit testing PHP apps with PHPUnit
Unit testing PHP apps with PHPUnitUnit testing PHP apps with PHPUnit
Unit testing PHP apps with PHPUnitMichelangelo van Dam
 
Into the ZF2 Service Manager
Into the ZF2 Service ManagerInto the ZF2 Service Manager
Into the ZF2 Service ManagerChris Tankersley
 
Zend Framework 2 : Dependency Injection
Zend Framework 2 : Dependency InjectionZend Framework 2 : Dependency Injection
Zend Framework 2 : Dependency InjectionAbdul Malik Ikhsan
 
PHPUnit best practices presentation
PHPUnit best practices presentationPHPUnit best practices presentation
PHPUnit best practices presentationThanh Robi
 
Meet a parallel, asynchronous PHP world
Meet a parallel, asynchronous PHP worldMeet a parallel, asynchronous PHP world
Meet a parallel, asynchronous PHP worldSteve Maraspin
 
Clean Unit Test Patterns
Clean Unit Test PatternsClean Unit Test Patterns
Clean Unit Test PatternsFrank Appel
 
Understanding Unit Testing
Understanding Unit TestingUnderstanding Unit Testing
Understanding Unit Testingikhwanhayat
 
Introduction to Unit Testing with PHPUnit
Introduction to Unit Testing with PHPUnitIntroduction to Unit Testing with PHPUnit
Introduction to Unit Testing with PHPUnitMichelangelo van Dam
 
Unit Testing Concepts and Best Practices
Unit Testing Concepts and Best PracticesUnit Testing Concepts and Best Practices
Unit Testing Concepts and Best PracticesDerek Smith
 
Zend Framework Workshop Parte2
Zend Framework Workshop Parte2Zend Framework Workshop Parte2
Zend Framework Workshop Parte2massimiliano.wosz
 
GAME ON! Integrating Games and Simulations in the Classroom
GAME ON! Integrating Games and Simulations in the Classroom GAME ON! Integrating Games and Simulations in the Classroom
GAME ON! Integrating Games and Simulations in the Classroom Brian Housand
 

En vedette (17)

ZF2 Modular Architecture - Taking advantage of it
ZF2 Modular Architecture - Taking advantage of itZF2 Modular Architecture - Taking advantage of it
ZF2 Modular Architecture - Taking advantage of it
 
Zend Framework 2 - PHPUnit
Zend Framework 2 - PHPUnitZend Framework 2 - PHPUnit
Zend Framework 2 - PHPUnit
 
Moduli su Zend Framework 2: come sfruttarli
Moduli su Zend Framework 2: come sfruttarliModuli su Zend Framework 2: come sfruttarli
Moduli su Zend Framework 2: come sfruttarli
 
Elegant Ways of Handling PHP Errors and Exceptions
Elegant Ways of Handling PHP Errors and ExceptionsElegant Ways of Handling PHP Errors and Exceptions
Elegant Ways of Handling PHP Errors and Exceptions
 
Asset management with Zend Framework 2
Asset management with Zend Framework 2Asset management with Zend Framework 2
Asset management with Zend Framework 2
 
Instant ACLs with Zend Framework 2
Instant ACLs with Zend Framework 2Instant ACLs with Zend Framework 2
Instant ACLs with Zend Framework 2
 
Unit testing PHP apps with PHPUnit
Unit testing PHP apps with PHPUnitUnit testing PHP apps with PHPUnit
Unit testing PHP apps with PHPUnit
 
Into the ZF2 Service Manager
Into the ZF2 Service ManagerInto the ZF2 Service Manager
Into the ZF2 Service Manager
 
Zend Framework 2 : Dependency Injection
Zend Framework 2 : Dependency InjectionZend Framework 2 : Dependency Injection
Zend Framework 2 : Dependency Injection
 
PHPUnit best practices presentation
PHPUnit best practices presentationPHPUnit best practices presentation
PHPUnit best practices presentation
 
Meet a parallel, asynchronous PHP world
Meet a parallel, asynchronous PHP worldMeet a parallel, asynchronous PHP world
Meet a parallel, asynchronous PHP world
 
Clean Unit Test Patterns
Clean Unit Test PatternsClean Unit Test Patterns
Clean Unit Test Patterns
 
Understanding Unit Testing
Understanding Unit TestingUnderstanding Unit Testing
Understanding Unit Testing
 
Introduction to Unit Testing with PHPUnit
Introduction to Unit Testing with PHPUnitIntroduction to Unit Testing with PHPUnit
Introduction to Unit Testing with PHPUnit
 
Unit Testing Concepts and Best Practices
Unit Testing Concepts and Best PracticesUnit Testing Concepts and Best Practices
Unit Testing Concepts and Best Practices
 
Zend Framework Workshop Parte2
Zend Framework Workshop Parte2Zend Framework Workshop Parte2
Zend Framework Workshop Parte2
 
GAME ON! Integrating Games and Simulations in the Classroom
GAME ON! Integrating Games and Simulations in the Classroom GAME ON! Integrating Games and Simulations in the Classroom
GAME ON! Integrating Games and Simulations in the Classroom
 

Similaire à Error Reporting in ZF2: form messages, custom error pages, logging

Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11Michelangelo van Dam
 
Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Shinya Ohyanagi
 
Bag Of Tricks From Iusethis
Bag Of Tricks From IusethisBag Of Tricks From Iusethis
Bag Of Tricks From IusethisMarcus Ramberg
 
Data::FormValidator Simplified
Data::FormValidator SimplifiedData::FormValidator Simplified
Data::FormValidator SimplifiedFred Moyer
 
Building Better Applications with Data::Manager
Building Better Applications with Data::ManagerBuilding Better Applications with Data::Manager
Building Better Applications with Data::ManagerJay Shirley
 
Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Michelangelo van Dam
 
Introduction to Zend Framework web services
Introduction to Zend Framework web servicesIntroduction to Zend Framework web services
Introduction to Zend Framework web servicesMichelangelo van Dam
 
Crafting beautiful software
Crafting beautiful softwareCrafting beautiful software
Crafting beautiful softwareJorn Oomen
 
WordPress as an application framework
WordPress as an application frameworkWordPress as an application framework
WordPress as an application frameworkDustin Filippini
 
Digital Mayflower - Data Pilgrimage with the Drupal Migrate Module
Digital Mayflower - Data Pilgrimage with the Drupal Migrate ModuleDigital Mayflower - Data Pilgrimage with the Drupal Migrate Module
Digital Mayflower - Data Pilgrimage with the Drupal Migrate ModuleErich Beyrent
 
HTML::FormFu talk for Sydney PM
HTML::FormFu talk for Sydney PMHTML::FormFu talk for Sydney PM
HTML::FormFu talk for Sydney PMDean Hamstead
 
Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Michelangelo van Dam
 
Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Michelangelo van Dam
 
The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of LithiumNate Abele
 

Similaire à Error Reporting in ZF2: form messages, custom error pages, logging (20)

Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11
 
Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2
 
Leveraging Symfony2 Forms
Leveraging Symfony2 FormsLeveraging Symfony2 Forms
Leveraging Symfony2 Forms
 
CakePHP workshop
CakePHP workshopCakePHP workshop
CakePHP workshop
 
Bag Of Tricks From Iusethis
Bag Of Tricks From IusethisBag Of Tricks From Iusethis
Bag Of Tricks From Iusethis
 
Data::FormValidator Simplified
Data::FormValidator SimplifiedData::FormValidator Simplified
Data::FormValidator Simplified
 
Building Better Applications with Data::Manager
Building Better Applications with Data::ManagerBuilding Better Applications with Data::Manager
Building Better Applications with Data::Manager
 
Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8
 
Introduction to Zend Framework web services
Introduction to Zend Framework web servicesIntroduction to Zend Framework web services
Introduction to Zend Framework web services
 
Crafting beautiful software
Crafting beautiful softwareCrafting beautiful software
Crafting beautiful software
 
WordPress as an application framework
WordPress as an application frameworkWordPress as an application framework
WordPress as an application framework
 
Digital Mayflower - Data Pilgrimage with the Drupal Migrate Module
Digital Mayflower - Data Pilgrimage with the Drupal Migrate ModuleDigital Mayflower - Data Pilgrimage with the Drupal Migrate Module
Digital Mayflower - Data Pilgrimage with the Drupal Migrate Module
 
HTML::FormFu talk for Sydney PM
HTML::FormFu talk for Sydney PMHTML::FormFu talk for Sydney PM
HTML::FormFu talk for Sydney PM
 
Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012
 
Moodle Quick Forms
Moodle Quick FormsMoodle Quick Forms
Moodle Quick Forms
 
Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12
 
Zend framework service
Zend framework serviceZend framework service
Zend framework service
 
Zend framework service
Zend framework serviceZend framework service
Zend framework service
 
The new form framework
The new form frameworkThe new form framework
The new form framework
 
The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of Lithium
 

Plus de Steve Maraspin

Architetture a Microservizi (con Kubernetes)
Architetture a Microservizi (con Kubernetes)Architetture a Microservizi (con Kubernetes)
Architetture a Microservizi (con Kubernetes)Steve Maraspin
 
How Agile changed Software Development
How Agile changed Software DevelopmentHow Agile changed Software Development
How Agile changed Software DevelopmentSteve Maraspin
 
Principi di Interaction Design
Principi di Interaction DesignPrincipi di Interaction Design
Principi di Interaction DesignSteve Maraspin
 
Customer Journey Mapping Workshop
Customer Journey Mapping WorkshopCustomer Journey Mapping Workshop
Customer Journey Mapping WorkshopSteve Maraspin
 
A (really) Quick Introduction to Event Storming
A (really) Quick Introduction to Event StormingA (really) Quick Introduction to Event Storming
A (really) Quick Introduction to Event StormingSteve Maraspin
 
Don't Make Me Think - There's no need (2014)
Don't Make Me Think - There's no need (2014)Don't Make Me Think - There's no need (2014)
Don't Make Me Think - There's no need (2014)Steve Maraspin
 
The Metaphor Fallacy (in Digital Product Development)
The Metaphor Fallacy (in Digital Product Development)The Metaphor Fallacy (in Digital Product Development)
The Metaphor Fallacy (in Digital Product Development)Steve Maraspin
 
Lean UX: Sviluppo Software Agile e Incentrato sull'Utente
Lean UX: Sviluppo Software Agile e Incentrato sull'UtenteLean UX: Sviluppo Software Agile e Incentrato sull'Utente
Lean UX: Sviluppo Software Agile e Incentrato sull'UtenteSteve Maraspin
 
La filosofia Lean nello sviluppo di prodotti digitali
La filosofia Lean nello sviluppo di prodotti digitaliLa filosofia Lean nello sviluppo di prodotti digitali
La filosofia Lean nello sviluppo di prodotti digitaliSteve Maraspin
 
Outcome not Output: A Story of Lean UX Adoption
Outcome not Output: A Story of Lean UX AdoptionOutcome not Output: A Story of Lean UX Adoption
Outcome not Output: A Story of Lean UX AdoptionSteve Maraspin
 
Don't Make me Think - There's no Need
Don't Make me Think - There's no NeedDon't Make me Think - There's no Need
Don't Make me Think - There's no NeedSteve Maraspin
 
Fare con Zend Framework 2 ciò che facevo con ZF1
Fare con Zend Framework 2 ciò che facevo con ZF1Fare con Zend Framework 2 ciò che facevo con ZF1
Fare con Zend Framework 2 ciò che facevo con ZF1Steve Maraspin
 
NoSQL Data Stores: Introduzione alle Basi di Dati Non Relazionali
NoSQL Data Stores: Introduzione alle Basi di Dati Non RelazionaliNoSQL Data Stores: Introduzione alle Basi di Dati Non Relazionali
NoSQL Data Stores: Introduzione alle Basi di Dati Non RelazionaliSteve Maraspin
 
Polyglot Persistance con PostgreSQL, CouchDB, MongoDB, Redis e OrientDB
Polyglot Persistance con PostgreSQL, CouchDB, MongoDB, Redis e OrientDBPolyglot Persistance con PostgreSQL, CouchDB, MongoDB, Redis e OrientDB
Polyglot Persistance con PostgreSQL, CouchDB, MongoDB, Redis e OrientDBSteve Maraspin
 
NoSQL, No Worries: Vecchi Problemi, Nuove Soluzioni
NoSQL, No Worries: Vecchi Problemi, Nuove SoluzioniNoSQL, No Worries: Vecchi Problemi, Nuove Soluzioni
NoSQL, No Worries: Vecchi Problemi, Nuove SoluzioniSteve Maraspin
 
Permettere al cliente di apprezzare l'approccio agile
Permettere al cliente di apprezzare l'approccio agilePermettere al cliente di apprezzare l'approccio agile
Permettere al cliente di apprezzare l'approccio agileSteve Maraspin
 
Let customers appreciate the agile workflow
Let customers appreciate the agile workflowLet customers appreciate the agile workflow
Let customers appreciate the agile workflowSteve Maraspin
 
Esempio di architettura distribuita basata su PHP, CouchDB e Mobile
Esempio di architettura distribuita basata su PHP, CouchDB e MobileEsempio di architettura distribuita basata su PHP, CouchDB e Mobile
Esempio di architettura distribuita basata su PHP, CouchDB e MobileSteve Maraspin
 
Striving towards better PHP code
Striving towards better PHP codeStriving towards better PHP code
Striving towards better PHP codeSteve Maraspin
 

Plus de Steve Maraspin (19)

Architetture a Microservizi (con Kubernetes)
Architetture a Microservizi (con Kubernetes)Architetture a Microservizi (con Kubernetes)
Architetture a Microservizi (con Kubernetes)
 
How Agile changed Software Development
How Agile changed Software DevelopmentHow Agile changed Software Development
How Agile changed Software Development
 
Principi di Interaction Design
Principi di Interaction DesignPrincipi di Interaction Design
Principi di Interaction Design
 
Customer Journey Mapping Workshop
Customer Journey Mapping WorkshopCustomer Journey Mapping Workshop
Customer Journey Mapping Workshop
 
A (really) Quick Introduction to Event Storming
A (really) Quick Introduction to Event StormingA (really) Quick Introduction to Event Storming
A (really) Quick Introduction to Event Storming
 
Don't Make Me Think - There's no need (2014)
Don't Make Me Think - There's no need (2014)Don't Make Me Think - There's no need (2014)
Don't Make Me Think - There's no need (2014)
 
The Metaphor Fallacy (in Digital Product Development)
The Metaphor Fallacy (in Digital Product Development)The Metaphor Fallacy (in Digital Product Development)
The Metaphor Fallacy (in Digital Product Development)
 
Lean UX: Sviluppo Software Agile e Incentrato sull'Utente
Lean UX: Sviluppo Software Agile e Incentrato sull'UtenteLean UX: Sviluppo Software Agile e Incentrato sull'Utente
Lean UX: Sviluppo Software Agile e Incentrato sull'Utente
 
La filosofia Lean nello sviluppo di prodotti digitali
La filosofia Lean nello sviluppo di prodotti digitaliLa filosofia Lean nello sviluppo di prodotti digitali
La filosofia Lean nello sviluppo di prodotti digitali
 
Outcome not Output: A Story of Lean UX Adoption
Outcome not Output: A Story of Lean UX AdoptionOutcome not Output: A Story of Lean UX Adoption
Outcome not Output: A Story of Lean UX Adoption
 
Don't Make me Think - There's no Need
Don't Make me Think - There's no NeedDon't Make me Think - There's no Need
Don't Make me Think - There's no Need
 
Fare con Zend Framework 2 ciò che facevo con ZF1
Fare con Zend Framework 2 ciò che facevo con ZF1Fare con Zend Framework 2 ciò che facevo con ZF1
Fare con Zend Framework 2 ciò che facevo con ZF1
 
NoSQL Data Stores: Introduzione alle Basi di Dati Non Relazionali
NoSQL Data Stores: Introduzione alle Basi di Dati Non RelazionaliNoSQL Data Stores: Introduzione alle Basi di Dati Non Relazionali
NoSQL Data Stores: Introduzione alle Basi di Dati Non Relazionali
 
Polyglot Persistance con PostgreSQL, CouchDB, MongoDB, Redis e OrientDB
Polyglot Persistance con PostgreSQL, CouchDB, MongoDB, Redis e OrientDBPolyglot Persistance con PostgreSQL, CouchDB, MongoDB, Redis e OrientDB
Polyglot Persistance con PostgreSQL, CouchDB, MongoDB, Redis e OrientDB
 
NoSQL, No Worries: Vecchi Problemi, Nuove Soluzioni
NoSQL, No Worries: Vecchi Problemi, Nuove SoluzioniNoSQL, No Worries: Vecchi Problemi, Nuove Soluzioni
NoSQL, No Worries: Vecchi Problemi, Nuove Soluzioni
 
Permettere al cliente di apprezzare l'approccio agile
Permettere al cliente di apprezzare l'approccio agilePermettere al cliente di apprezzare l'approccio agile
Permettere al cliente di apprezzare l'approccio agile
 
Let customers appreciate the agile workflow
Let customers appreciate the agile workflowLet customers appreciate the agile workflow
Let customers appreciate the agile workflow
 
Esempio di architettura distribuita basata su PHP, CouchDB e Mobile
Esempio di architettura distribuita basata su PHP, CouchDB e MobileEsempio di architettura distribuita basata su PHP, CouchDB e Mobile
Esempio di architettura distribuita basata su PHP, CouchDB e Mobile
 
Striving towards better PHP code
Striving towards better PHP codeStriving towards better PHP code
Striving towards better PHP code
 

Dernier

Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersRaghuram Pandurangan
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
unit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxunit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxBkGupta21
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxLoriGlavin3
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxLoriGlavin3
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfMounikaPolabathina
 

Dernier (20)

Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information Developers
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
unit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxunit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptx
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdf
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 

Error Reporting in ZF2: form messages, custom error pages, logging

  • 1. Error Reporting in Zend Framework 2 Zend Framework Day – Turin, Italy – 07/02/2014
  • 11.
  • 15. User Input = Mistake Source
  • 17. User Privacy Concerns • Over 40% of online shoppers are very concerned over the use of personal information • Public opinion polls have revealed a general desire among Internet users to protect their privacy Online Privacy: A Growing Threat. - Business Week, March 20, 2000, 96. Internet Privacy in ECommerce: Framework, Review, and Opportunities for Future Research - Proceedings of the 41st Hawaii International Conference on System Sciences - 2008
  • 21. 21
  • 22. Creating A Form in ZF2 <?php namespace ApplicationForm; use ZendFormForm; class ContactForm extends Form { public function __construct() { parent::__construct(); // ... } //... }
  • 23. Creating A Form in ZF2 <?php namespace ApplicationForm; use ZendFormForm; class ContactForm extends Form { public function __construct() { parent::__construct(); // ... } //... }
  • 24. Adding Form Fields public function init() { $this->setName('contact'); $this->setAttribute('method', 'post'); […].. $this->add(array('name' => 'email', 'type' => 'text', 'options' => array( 'label' => 'Name', ), ); $this->add(array('name' => 'message', 'type' => 'textarea', 'options' => array( 'label' => 'Message', ), ); //. […].. }
  • 25. Adding Form Fields public function init() { $this->setName('contact'); $this->setAttribute('method', 'post'); […].. $this->add(array('name' => 'email', 'type' => 'text', 'options' => array( 'label' => 'Name', ), ); $this->add(array('name' => 'message', 'type' => 'textarea', 'options' => array( 'label' => 'Message', ), ); //. […].. }
  • 28. Validation: inputFilter <?php namespace ApplicationForm; […] class ContactFilter extends InputFilter { public function __construct() { // filters go here } }
  • 29. Validation: inputFilter <?php namespace ApplicationForm; […] class ContactFilter extends InputFilter { public function __construct() { // filters go here } }
  • 30. Required Field Validation $this->add(array( 'name' => 'email', 'required' => true, 'filters' => array( array( 'name' => 'StringTrim'), ), 'validators' => array( array( 'name' => 'EmailAddress', ) ) ));
  • 31. Required Field Validation $this->add(array( 'name' => 'email', 'required' => true, 'filters' => array( array( 'name' => 'StringTrim'), ), 'validators' => array( array( 'name' => 'EmailAddress', ) ) ));
  • 32. InputFilter Usage <?php namespace ApplicationController; […] class IndexController extends AbstractActionController { public function contactAction() { $form = new Contact(); $filter = new ContactFilter(); $form->setInputFilter($filter); return new ViewModel(array( 'form' => $form ); } }
  • 33. InputFilter Usage <?php namespace ApplicationController; […] class IndexController extends AbstractActionController { public function contactAction() { $form = new Contact(); $filter = new ContactFilter(); $form->setInputFilter($filter); return new ViewModel(array( 'form' => $form ); } }
  • 36. Error Message Customization $this->add(array( 'name' => 'email', 'required' => true, 'filters' => array( array('name' => 'StringTrim'), ), 'validators' => array( array('name' =>'NotEmpty', 'options' => array( 'messages' => array( NotEmpty::IS_EMPTY => 'We need an '. 'e-mail address to be able to get back to you' ), ), ), array('name' => 'EmailAddress'), ) ));
  • 37. Error Message Customization $this->add(array( 'name' => 'email', 'required' => true, 'filters' => array( array('name' => 'StringTrim'), ), 'validators' => array( array('name' =>'NotEmpty', 'options' => array( 'messages' => array( NotEmpty::IS_EMPTY => 'We need an '. 'e-mail address to be able to get back to you' ), ), ), array('name' => 'EmailAddress'), ) ));
  • 38. More than we need…
  • 39. Check Chain $this->add(array( 'name' => 'email', 'required' => true, 'filters' => array( array('name' => 'StringTrim'), ), 'validators' => array( array('name' =>'NotEmpty', 'options' => array( 'messages' => array( NotEmpty::IS_EMPTY => 'We need an '. 'e-mail address to be able to get back to you' ), ), 'break_chain_on_failure' => true, ), array('name' => 'EmailAddress'), ) ));
  • 42.
  • 43.
  • 45. A few tips: • • • 45 Provide the user with a solution to the problem Do not use technical jargon, use terminology that your audience understands Avoid uppercase text and exclamation points
  • 47. Condensing N messages into 1 $this->add(array( 'name' => 'email', 'required' => true, 'validators' => array( array('name' =>'NotEmpty', 'options' => array( 'messages' => array( NotEmpty::IS_EMPTY => 'We need an '. 'e-mail address to be able to get back to you' )), 'break_chain_on_failure' => true, ), array('name' => 'EmailAddress', 'options' => array( 'message' => 'E-Mail address does not seem to be valid. Please make sure it contains the @ symbol and a valid domain name.', )));
  • 48. Condensing N messages into 1 $this->add(array( 'name' => 'email', 'required' => true, 'validators' => array( array('name' =>'NotEmpty', 'options' => array( 'messages' => array( NotEmpty::IS_EMPTY => 'We need an '. 'e-mail address to be able to get back to you' )), 'break_chain_on_failure' => true, ), array('name' => 'EmailAddress', 'options' => array( 'message' => 'E-Mail address does not seem to be valid. Please make sure it contains the @ symbol and a valid domain name.', )));
  • 49. Messages VS message $this->add(array( 'name' => 'email', 'required' => true, 'validators' => array( array('name' =>'NotEmpty', 'options' => array( 'messages' => array( NotEmpty::IS_EMPTY => 'We need an '. 'e-mail address to be able to get back to you' )), 'break_chain_on_failure' => true, ), array('name' => 'EmailAddress', 'options' => array( 'message' => 'E-Mail address does not seem to be valid. Please make sure it contains the @ symbol and a valid domain name.', )));
  • 51. Default Message Translation public function onBootstrap(MvcEvent $e) { $translator = $e->getApplication() ->getServiceManager()->get('translator'); $translator->addTranslationFile( 'phpArray', __DIR__ . '/../../vendor/zendframework/zendframework/'. 'resources/languages/it/Zend_Validate.php', 'default', 'it_IT' ); AbstractValidator::setDefaultTranslator($translator); }
  • 52. Custom Message Translation $this->add(array( 'name' => 'email', 'required' => true, 'validators' => array( array('name' =>'NotEmpty', 'options' => array( 'translator' => $translator, 'message' => $translator->translate( 'Make sure your e-mail address contains the @ symbol and a valid domain name.' )), 'break_chain_on_failure' => true, ), )));
  • 53. Form Factory $translator = $I_services->get('translator'); $I_form = new Contact(); $I_filter = new ContactFilter($translator); $I_form->setInputFilter($I_filter); return $I_form;
  • 56. 56
  • 57.
  • 58. Error Display Configuration Skeleton Applicaton Configuration
  • 59. Hiding Exception Traces 'view_manager' => array( 'display_not_found_reason' => false, 'display_exceptions' => false, 'doctype' => 'HTML5', 'not_found_template' => 'error/404', 'exception_template' => 'error/index', 'template_map' => array( 'layout/layout' => __DIR__ . '/../view/layout/layout.phtml', 'application/index/index'=> __DIR__ . '/../view/application/index/index.phtml', 'error/404' => __DIR__ . '/../view/error/404.phtml', 'error/index' => __DIR__ . '/../view/error/index.phtml', ), 'template_path_stack' => array( __DIR__ . '/../view', ), ),
  • 60. Hiding Exception Traces 'view_manager' => array( 'display_not_found_reason' => false, 'display_exceptions' => false, 'doctype' => 'HTML5', 'not_found_template' => 'error/404', 'exception_template' => 'error/index', 'template_map' => array( 'layout/layout' => __DIR__ . '/../view/layout/layout.phtml', 'application/index/index'=> __DIR__ . '/../view/application/index/index.phtml', 'error/404' => __DIR__ . '/../view/error/404.phtml', 'error/index' => __DIR__ . '/../view/error/index.phtml', ), 'template_path_stack' => array( __DIR__ . '/../view', ), ),
  • 61.
  • 62. Custom Error Pages 'view_manager' => array( 'display_not_found_reason' => false, 'display_exceptions' => false, 'doctype' => 'HTML5', 'not_found_template' => 'error/404', 'exception_template' => 'error/index', 'template_map' => array( 'layout/layout' => __DIR__ . '/../view/layout/layout.phtml', 'application/index/index'=> __DIR__ . '/../view/application/index/index.phtml', 'error/404' => __DIR__ . '/../view/error/404.phtml', 'error/index' => __DIR__ . '/../view/error/index.phtml', ), 'template_path_stack' => array( __DIR__ . '/../view', ), ),
  • 63.
  • 64. How about PHP Errors? class IndexController extends AbstractActionController { public function indexAction() { 1/0; return new ViewModel(); } }
  • 65. How about PHP Errors? class IndexController extends AbstractActionController { public function indexAction() { 1/0; return new ViewModel(); } }
  • 66.
  • 68. What can we do?
  • 69. Handling PHP Errors public function onBootstrap(MvcEvent $I_e) { […] set_error_handler(array('ApplicationModule','handlePhpErrors')); } public static function handlePhpErrors($i_type, $s_message, $s_file, $i_line) { if (!($i_type & error_reporting())) { return }; throw new Exception("Error: " . $s_message . " in file " . $s_file . " at line " . $i_line); }
  • 70. What happens now? class IndexController extends AbstractActionController { public function indexAction() { 1/0; return new ViewModel(); } }
  • 71.
  • 72. Now… what if? class IndexController extends AbstractActionController { public function indexAction() { $doesNotExist->doSomething(); return new ViewModel(); } }
  • 73. Fatal error: Call to a member function doSomething() on a non-object in /srv/apps/zfday/module/Application/src/Application/Controller/IndexController.php on line 20
  • 75. Fatal Error Handling public function onBootstrap(MvcEvent $I_e) { […] $am_config = $I_application->getConfig(); $am_environmentConf = $am_config['mvlabs_environment']; // Fatal Error Recovery if (array_key_exists('recover_from_fatal', $am_environmentConf) && $am_environmentConf['recover_from_fatal']) { $s_redirectUrl = $am_environmentConf['redirect_url']; } $s_callback = null; if (array_key_exists('fatal_errors_callback', $am_environmentConf)) { $s_callback = $am_environmentConf['fatal_errors_callback']; } register_shutdown_function(array('ApplicationModule', 'handleFatalPhpErrors'), $s_redirectUrl, $s_callback); }
  • 76. Fatal Error Handling /** * Redirects user to nice page after fatal has occurred */ public static function handleFatalPhpErrors($s_redirectUrl, $s_callback = null) { if (php_sapi_name() != 'cli' && @is_Array($e = @get_last())) { if (null != $s_callback) { // This is the most stuff we can get. // New context outside of framework scope $m_code = isset($e['type']) ? $e['type'] : 0; $s_msg = isset($e['message']) ? $e['message']:''; $s_file = isset($e['file']) ? $e['file'] : ''; $i_line = isset($e['line']) ? $e['line'] : ''; $s_callback($s_msg, $s_file, $i_line); } header("location: ". $s_redirectUrl); } return false; }
  • 77. Fatal Error Handling 'mvlabs_environment' => array( 'exceptions_from_errors' => true, 'recover_from_fatal' => true, 'fatal_errors_callback' => function($s_msg, $s_file, $s_line) { return false; }, 'redirect_url' => '/error', 'php_settings' => array( 'error_reporting' => E_ALL, 'display_errors' => 'Off', 'display_startup_errors' => 'Off', ), ),
  • 78. PHP Settings Conf 'mvlabs_environment' => array( 'exceptions_from_errors' => true, 'recover_from_fatal' => true, 'fatal_errors_callback' => function($s_msg, $s_file, $s_line) { return false; }, 'redirect_url' => '/error', 'php_settings' => array( 'error_reporting' => E_ALL, 'display_errors' => 'Off', 'display_startup_errors' => 'Off', ), ),
  • 79. PHP Settings public function onBootstrap(MvcEvent $I_e) { […] foreach($am_phpSettings as $key => $value) { ini_set($key, $value); } }
  • 81. CUSTOMER SUPPORT TEAM REACTION http://www.flickr.com/photos/18548283@N00/8030280738
  • 82.
  • 87. Index.php // Application wide configuration $am_conf = $am_originalConf = require 'config/application.config.php'; // Environment specific configuration $s_environmentConfFile = 'config/application.'.$s_env.'.config.php'; if (file_exists($s_environmentConfFile) && is_readable($s_environmentConfFile)) { // Specific environment configuration merge $am_environmentConf = require $s_environmentConfFile; $am_conf = ZendStdlibArrayUtils::merge($am_originalConf, $am_environmentConf ); } // Additional Specific configuration files are also taken into account $am_conf["module_listener_options"]["config_glob_paths"][] = 'config/autoload/{,*.}' . $s_env . '.php'; ZendMvcApplication::init($am_conf)->run();
  • 90. Enabling Environment Confs // Application nominal environment $am_conf = $am_originalConf = require 'config/application.config.php'; // Environment specific configuration $s_environmentConfFile = 'config/application.'.$s_env.'.config.php'; // Do we have a specific configuration file? if (file_exists($s_environmentConfFile) && is_readable($s_environmentConfFile)) { // Specific environment configuration merge $am_environmentConf = require $s_environmentConfFile; $am_conf = ZendStdlibArrayUtils::merge($am_originalConf, $am_environmentConf ); } // Additional Specific configuration files are also taken into account $am_conf["module_listener_options"]["config_glob_paths"][] = 'config/autoload/{,*.}' . $s_env . '.php'; ZendMvcApplication::init($am_conf)->run();
  • 92. index.php Check // What environment are we in? $s_env = getenv('APPLICATION_ENV'); if (empty($s_env)) { throw new Exception('Environment not set.'. ' Cannot continue. Too risky!'); }
  • 93. Apache Config File <VirtualHost *:80> DocumentRoot /srv/apps/zfday/public ServerName www.dev.zfday.it SetEnv APPLICATION_ENV "dev" <Directory /srv/apps/zfday/public> AllowOverride FileInfo </Directory> </VirtualHost>
  • 95. Why Log? Troubleshooting • Stats Generation • Compliance • 95
  • 96. Zend Log $logger = new ZendLogLogger; $writer = new ZendLogWriterStream('/var/log/app.log'); $logger->addWriter($writer); $logger->info('Informational message'); $logger->log(ZendLogLogger::EMERG, 'Emergency message');
  • 97. Zend Log $logger = new ZendLogLogger; $writer = new ZendLogWriterStream('/var/log/app.log'); $logger->addWriter($writer); $logger->info('Informational message'); $logger->log(ZendLogLogger::EMERG, 'Emergency message'); ZendLogLogger::registerErrorHandler($logger); ZendLogLogger::registerExceptionHandler($logger);
  • 105. Filter Example $logger = new ZendLogLogger; $writer1 = new ZendLogWriterStream('/var/log/app.log'); $logger->addWriter($writer1); $writer2 = new ZendLogWriterStream('/var/log/err.log'); $logger->addWriter($writer2); $filter = new ZendLogFilterPriority(Logger::CRIT); $writer2->addFilter($filter); $logger->info('Informational message'); $logger->log(ZendLogLogger::CRIT, 'Emergency message');
  • 106. Monolog use MonologLogger; use MonologHandlerStreamHandler; $log = new Logger('name'); $log->pushHandler(new StreamHandler('/var/log/app.log', Logger::WARNING)); $log->addWarning('Foo'); $log->addError('Bar');
  • 108. How to log? class IndexController { public function helloAction() { return new ViewModel('msg' =>"Hello!"); } }
  • 110. Logging Within Controller class GreetingsController { public function helloAction() { $I_logger = new Logger(); $I_logger->log("We just said Hello!"); return new ViewModel('msg' =>"Hello!"); } }
  • 111. Single Responsability Violation class GreetingsController { public function helloAction() { $I_logger = new Logger(); $I_logger->log("We just said Hello!"); return new ViewModel('msg' =>"Hello!"); } }
  • 112. Fat Controllers class GreetingsController { public function helloAction() { $I_logger = new Logger(); $I_logger->log("We just said Hello!"); $I_mailer = new Mailer(); $I_mailer->mail($s_msg); $I_queue = new Queue(); $I_queue->add($s_msg); return new ViewModel('msg' =>"Hello!"); } }
  • 114. What can we do?
  • 115. Handling Events class Module { public function onBootstrap(MvcEvent $e) { $eventManager = $e->getApplication() ->getEventManager(); $moduleRouteListener = new ModuleRouteListener(); $moduleRouteListener->attach($eventManager); $logger = $sm->get('logger'); $eventManager->attach('wesaidHello', function(MvcEvent $event) use ($logger) { $logger->log($event->getMessage()); ); } }
  • 116. Triggering An Event class GreetingsController { public function helloAction() { $this->eventManager ->trigger('wesaidHello', $this, array('greeting' => 'Hello!') ); return new ViewModel('msg' => "Hello!"); } }
  • 121. Handling Framework Errors class Module { public function onBootstrap(MvcEvent $e) { $eventManager = $e->getApplication() ->getEventManager(); $moduleRouteListener = new ModuleRouteListener(); $moduleRouteListener->attach($eventManager); $logger = $sm->get('logger'); $eventManager->attach(MvcEvent::EVENT_RENDER_ERROR, function(MvcEvent $e) use ($logger) { $logger->info('An exception has Happened ' . $e->getResult()->exception->getMessage()); }, -200); ); } }
  • 123. Stuff to take home 1. 2. 3. 123 When reporting errors, make sure to be nice with users Different error reporting strategies could be useful for different environments The event manager reduces coupling and provides flexibility
  • 124.
  • 125.
  • 126.
  • 129. Starting Things Up input { stdin { } } output { stdout { codec => rubydebug } }
  • 130. Starting Things Up input { stdin { } } output { stdout { codec => rubydebug } } java -jar logstash-1.3.3-flatjar.jar agent -f sample.conf
  • 131. Integrated Elasticsearch input { file { path => ["/opt/logstash/example.log"] } } output { stdout { codec => rubydebug } elasticsearch { embedded => true } } java -jar logstash-1.3.3-flatjar.jar agent -f elastic.conf
  • 132. Integrated Web Interface input { file { path => ["/opt/logstash/example.log"] } } output { stdout { codec => rubydebug } elasticsearch { embedded => true } } java -jar logstash.jar agent -f elastic.conf --web
  • 133. Kibana
  • 134. Thank you for your attention Stefano Maraspin @maraspin