SlideShare a Scribd company logo
1 of 65
Download to read offline
Ch-ch-anges
 C a k e P H P   2 . 0
CakePHP 2.0
No more PHP4, PHP 5.2.6+

Many re-factored/re-built internal & external
API’s

New features!

Faster!

Updated conventions.
PHP5
Use native features:

  Exceptions.

  Filter ext.

  PDO.

  SPL.

  json_encode()
Conventions
Updated conventions

 ClassName = FileName.php

 View/Helper/HtmlHelper.php =>
 HtmlHelper.

 CamelCased directories.

 Preparing for PHP5.3 and PSR-0
New loader


App::import() - Old and busted.

App::uses() - New hawtness.
Examples
Examples
App::uses(‘AuthComponent’, ‘Controller/Component’);
Examples
App::uses(‘AuthComponent’, ‘Controller/Component’);




     Classname
Examples
App::uses(‘AuthComponent’, ‘Controller/Component’);




     Classname                     Package
Examples
App::uses(‘AuthComponent’, ‘Controller/Component’);




     Classname                     Package



      App::uses(‘CakeEmail’, ‘Network/Email’);
Examples
App::uses(‘AuthComponent’, ‘Controller/Component’);




     Classname                     Package



      App::uses(‘CakeEmail’, ‘Network/Email’);




      Classname
Examples
App::uses(‘AuthComponent’, ‘Controller/Component’);




     Classname                     Package



      App::uses(‘CakeEmail’, ‘Network/Email’);




      Classname                    Package
Packages

Use App::build() to define paths where any
package lives.

Sensible defaults come built in.

Undefined packages default to checking
app/Lib
paths


Use App::build() to define paths where
packages can be found.

Can use App::PREPEND and App::APPEND
to control insertion order.
Bad things
 happen
Exceptions

Object::cakeError() is dead.

New Exceptions & Exception handling
replace it.

More extensible and configurable handling.
Example
 1   <?php
 2   // Customize the renderer.
 3   Configure::write('Exception', array(
 4       'handler' => 'ErrorHandler::handleException',
 5       'renderer' => 'MyCustomExceptionRenderer',
 6       'log' => true
 7   ));
 8
 9   // Replace everything.
10   Configure::write('Exception', array(
11       'handler' => function ($e) {
12           echo 'Oh noes';
13       }
14   ));
Built-in exceptions
All previous Object::cakeError() are
exceptions.

Improved testing.

Suite of HTTP exceptions. Great for error
pages.

CakeException for development errors.
Treated as 500 errors in production.
HTTP Exceptions

Most common HTTP exceptions are built in.

The names are what you would expect.

Configured Exception handler will get the
exceptions and render an error page.
HttpExceptions
1 <?php
2 public function view($id = null) {
3     $this->Tag->id = $id;
4     if (!$this->Tag->exists()) {
5         throw new NotFoundException(__('Invalid tag'));
6     }
7     $this->set('tag', $this->Tag->read(null, $id));
8 }
Error Configuration

 Configure used for error/exception settings.

 Sensible defaults.

   Uses Debugger in development

   Logs errors in production.

 You can change out the whole thing.
i18n
i18n


No more true.

Automatic sprintf()
Examples


__(‘Some string’)
Always returns.

__(‘Some %s’, $value);
Does what you want it to.
Unify disparate
     apis
Unify & syngergize

Helper, Components, Behaviors & Tasks.

Similar, but interacting with each was slightly
different.

Collection objects unify all of them.

  HelperCollection, ComponentCollection,
  TaskCollection, BehaviorCollection
Collections

Load objects at runtime.

Unload objects.

Alias objects.

Trigger callbacks.
Loading

$Html = $this->Helpers->load(‘Html’, $settings);


$this->Html works from that point
forward.

The same API exists for components, tasks,
behaviors.
Aliasing

1 <?php
2 public $helpers = array(
3     'Html' => array(
4         'className' => 'MyHtmlHelper'
5     )
6 );
Aliasing

Once an alias is created, that alias is used
everywhere.

With the above controller code, all other
Helpers would use MyHtmlHelper for
$this->Html.
Unload and disable


$this->Components->disable(‘Auth’);

$this->Components->enable(‘Auth’);

$this->Components->unload(‘Auth’);
Callbacks

$this->Helpers->trigger(‘beforeRender’, array
(&$this));

Fires method on all enabled objects.

Implement custom hooks in base classes.
Console
Console
     improvements
Coloured output & output levels.

Less coupled & easier to test.

Better input handling.

Generated help.

XML help. Good for integration with other
tools.
COLORZ

Simple formatting to add styles to output.
$this->out(‘<warning>Uh oh</warning>’);


$this->out(‘<error>Kaboom</error>’);


$this->out(‘<info>Hi</info>’, 1, Shell::VERBOSE);
Input handling

More unix-y input handling.

Long and short options.

Validated options.

Boolean options.

Required arguments.
Generated help

Defining command structure with
ConsoleOptionParser means you get help for
free.

--help and -h supported by all shells.

--help xml generates xml help.
Request &
Response
CakeRequest

Consolidates request interrogation logic.

$this->request everywhere.

Lower memory use by not copying arrays
everywhere.

Backwards compatible read only interface
still around.
CakeResponse

Consolidates response generation.

$this->response everywhere.

Deprecated methods still around.

Controllers can return response objects.
example
1 <?php
2 class PostsController extends AppController {
3     public function simple() {
4         return new CakeResponse(array(
5             'body' => 'Simple response'
6         ));
7     }
8 }
Sessions
Sessions


Sessions were tough in the past.

Custom session handlers weren’t on the same
field as core ones.
Sessions

Core, App, and Plugin session handlers all
work the same.

CakeSessionInterface interface has to be
implemented.

Same built-in options exist.
Using built-ins
 1   <?php
 2   Configure::write('Session', array(
 3       'defaults' => 'php'
 4   ));
 5   Configure::write('Session', array(
 6       'defaults' => 'database'
 7   ));
 8   Configure::write('Session', array(
 9       'defaults' => 'cache',
10       'handler' => array(
11           'config' => 'session'
12       )
13   ));
Using an app/plugin
  1   <?php
  2   Configure::write('Session', array(
  3       'defaults' => 'database',
  4       'handler' => array(
  5           'engine' => 'Custom'
  6       )
  7   ));
  8   Configure::write('Session', array(
  9       'defaults' => 'php',
 10       'handler' => array(
 11           'engine' => 'Plugin.SessionHandler'
 12       ),
 13       'ini' => array(
 14           'session.cookie_httponly' => true
 15       )
 16   ));
Authorization
AuthComponent

Split into authorization and authentication
adapters.

Easier to modify and extend.

No magic logins.

No magic hashing of passwords.
Built-ins
Authentication     Authorization

  Form.              Controller.

  HTTP Basic.        Actions (Acl)

  HTTP Digest.       CRUD (Acl)

  custom             custom
Logging in
 1 <?php
 2 class UsersController extends AppController {
 3     public function login() {
 4         if ($this->request->is('post')) {
 5             if ($this->Auth->login()) {
 6                 $this->Session->setFlash('Welcome back!');
 7                 $this->redirect($this->Auth->redirect());
 8             } else {
 9                 $this->Session->setFlash('Login credentials were invalid.');
10             }
11         }
12     }
13 }
Auth Configuration


Way less, because there is less magic.

Easier for beginners to grok.

Easier for veterans to customize.
Email
Email

Decomposed into several classes.

Email is easily accessible from models &
shells.

EmailComponent is deprecated, because it
doesn’t really add anything at this point.
Simple Example
1   <?php
2   App::uses('CakeEmail', 'Network/Email');
3   $mail = new CakeEmail();
4   $mail->from('mark.story@gmail.com', 'Mark Story')
5       ->to('steve@apple.com', 'Steve Jobs')
6       ->subject('Love the new imacs')
7       ->send('I <3 you so much.');
Templates
 1   <?php
 2   App::uses('CakeEmail', 'Network/Email');
 3   $mail = new CakeEmail();
 4   $mail->from('mark.story@gmail.com', 'Mark Story')
 5       ->to('steve@apple.com', 'Steve Jobs')
 6       ->subject('Love the new imacs')
 7       ->template('love_you', 'simple')
 8       ->emailFormat('html')
 9       ->viewVars($vars)
10       ->send();
Mail Transports


Extracted out as separate classes.

3 built-in transports, and you can make your
own.
Testing
Testing

PHPUnit is the de-facto standard.

SimpleTest is less feature rich, and didn’t
have a PHP5 compatible version when we
started.

Tune in for my talk on PHPUnit.
Performance
All win
Lazy loading everywhere it made sense.

  Components, helpers, associated models.

Removed most getInstance() methods.

New conventions mean less Inflector calls.

Streamlined dispatch cycle.

Persistent dbo cache.
Hello World (rps)
350.0



262.5
                                         CakePHP 1.3.11
                                         CakePHP 2.0-beta
175.0



 87.5



   0
                 Hello world

        siege -b -c 20 -r 100 http://localhost/hello/world
Basic blog (rps)
50.0



37.5
                                      CakePHP 1.3.11
                                      CakePHP 2.0-beta
25.0



12.5



  0
              Basic blog

       siege -b -c 20 -r 100 http://localhost/posts
Functions called
                                       Hello World     Basic Blog
500



375



250



125



  0
       CakePHP 1.3.11                   CakePHP 2.0-beta
              Collected using webgrind and xdebug
Questions?

More Related Content

What's hot

Introduction to puppet
Introduction to puppetIntroduction to puppet
Introduction to puppet
Habeeb Rahman
 
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
singingfish
 
parenscript-tutorial
parenscript-tutorialparenscript-tutorial
parenscript-tutorial
tutorialsruby
 
Debugging over tcp and http
Debugging over tcp and httpDebugging over tcp and http
Debugging over tcp and http
Kaniska Mandal
 

What's hot (20)

Introduction to puppet
Introduction to puppetIntroduction to puppet
Introduction to puppet
 
Rspec API Documentation
Rspec API DocumentationRspec API Documentation
Rspec API Documentation
 
Master the New Core of Drupal 8 Now: with Symfony and Silex
Master the New Core of Drupal 8 Now: with Symfony and SilexMaster the New Core of Drupal 8 Now: with Symfony and Silex
Master the New Core of Drupal 8 Now: with Symfony and Silex
 
Puppet at GitHub / ChatOps
Puppet at GitHub / ChatOpsPuppet at GitHub / ChatOps
Puppet at GitHub / ChatOps
 
You are not_hiding_from_me_.net
You are not_hiding_from_me_.netYou are not_hiding_from_me_.net
You are not_hiding_from_me_.net
 
Grand Rapids PHP Meetup: Behavioral Driven Development with Behat
Grand Rapids PHP Meetup: Behavioral Driven Development with BehatGrand Rapids PHP Meetup: Behavioral Driven Development with Behat
Grand Rapids PHP Meetup: Behavioral Driven Development with Behat
 
Puppet at Pinterest
Puppet at PinterestPuppet at Pinterest
Puppet at Pinterest
 
Cooking Perl with Chef
Cooking Perl with ChefCooking Perl with Chef
Cooking Perl with Chef
 
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014
 
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
 
Web develop in flask
Web develop in flaskWeb develop in flask
Web develop in flask
 
Nginx pres
Nginx presNginx pres
Nginx pres
 
Writing Software not Code with Cucumber
Writing Software not Code with CucumberWriting Software not Code with Cucumber
Writing Software not Code with Cucumber
 
Drupal 8: Huge wins, a Bigger Community, and why you (and I) will Love it
Drupal 8: Huge wins, a Bigger Community, and why you (and I) will Love itDrupal 8: Huge wins, a Bigger Community, and why you (and I) will Love it
Drupal 8: Huge wins, a Bigger Community, and why you (and I) will Love it
 
parenscript-tutorial
parenscript-tutorialparenscript-tutorial
parenscript-tutorial
 
Top 50 Interview Questions and Answers in CakePHP
Top 50 Interview Questions and Answers in CakePHPTop 50 Interview Questions and Answers in CakePHP
Top 50 Interview Questions and Answers in CakePHP
 
Python tools for testing web services over HTTP
Python tools for testing web services over HTTPPython tools for testing web services over HTTP
Python tools for testing web services over HTTP
 
2 introduction-php-mvc-cakephp-m2-installation-slides
2 introduction-php-mvc-cakephp-m2-installation-slides2 introduction-php-mvc-cakephp-m2-installation-slides
2 introduction-php-mvc-cakephp-m2-installation-slides
 
Maven 3.0 at Øredev
Maven 3.0 at ØredevMaven 3.0 at Øredev
Maven 3.0 at Øredev
 
Debugging over tcp and http
Debugging over tcp and httpDebugging over tcp and http
Debugging over tcp and http
 

Similar to Ch ch-changes cake php2

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
Michelangelo van Dam
 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207
patter
 

Similar to Ch ch-changes cake php2 (20)

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
 
PHPunit and you
PHPunit and youPHPunit and you
PHPunit and you
 
Building Testable PHP Applications
Building Testable PHP ApplicationsBuilding Testable PHP Applications
Building Testable PHP Applications
 
Workshop quality assurance for php projects - ZendCon 2013
Workshop quality assurance for php projects - ZendCon 2013Workshop quality assurance for php projects - ZendCon 2013
Workshop quality assurance for php projects - ZendCon 2013
 
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
 
Workshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfastWorkshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfast
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい
 
Building and Incredible Machine with Pipelines and Generators in PHP (IPC Ber...
Building and Incredible Machine with Pipelines and Generators in PHP (IPC Ber...Building and Incredible Machine with Pipelines and Generators in PHP (IPC Ber...
Building and Incredible Machine with Pipelines and Generators in PHP (IPC Ber...
 
Lean Php Presentation
Lean Php PresentationLean Php Presentation
Lean Php Presentation
 
PHPSpec BDD Framework
PHPSpec BDD FrameworkPHPSpec BDD Framework
PHPSpec BDD Framework
 
Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5
 
Debugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 VersionDebugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 Version
 
Quality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStormQuality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStorm
 
Debugging: Rules & Tools
Debugging: Rules & ToolsDebugging: Rules & Tools
Debugging: Rules & Tools
 
Cake php
Cake phpCake php
Cake php
 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207
 
Fatc
FatcFatc
Fatc
 
Heavy Web Optimization: Backend
Heavy Web Optimization: BackendHeavy Web Optimization: Backend
Heavy Web Optimization: Backend
 
From CakePHP to Laravel
From CakePHP to LaravelFrom CakePHP to Laravel
From CakePHP to Laravel
 
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
 

More from markstory

Introduction to Twig
Introduction to TwigIntroduction to Twig
Introduction to Twig
markstory
 
Owasp top 10
Owasp top 10Owasp top 10
Owasp top 10
markstory
 
Intro to continuous integration
Intro to continuous integration Intro to continuous integration
Intro to continuous integration
markstory
 

More from markstory (20)

Dependency injection in CakePHP
Dependency injection in CakePHPDependency injection in CakePHP
Dependency injection in CakePHP
 
Safer, More Helpful CakePHP
Safer, More Helpful CakePHPSafer, More Helpful CakePHP
Safer, More Helpful CakePHP
 
CakePHP - The Road Ahead
CakePHP - The Road AheadCakePHP - The Road Ahead
CakePHP - The Road Ahead
 
Future of HTTP in CakePHP
Future of HTTP in CakePHPFuture of HTTP in CakePHP
Future of HTTP in CakePHP
 
CakePHP mistakes made 2015
CakePHP mistakes made 2015CakePHP mistakes made 2015
CakePHP mistakes made 2015
 
New in cakephp3
New in cakephp3New in cakephp3
New in cakephp3
 
PHP WTF
PHP WTFPHP WTF
PHP WTF
 
CakePHP 3.0 and beyond
CakePHP 3.0 and beyondCakePHP 3.0 and beyond
CakePHP 3.0 and beyond
 
CakePHP mistakes made confoo 2015
CakePHP mistakes made confoo 2015CakePHP mistakes made confoo 2015
CakePHP mistakes made confoo 2015
 
CakePHP mistakes made
CakePHP mistakes madeCakePHP mistakes made
CakePHP mistakes made
 
Performance and optimization CakeFest 2014
Performance and optimization CakeFest 2014Performance and optimization CakeFest 2014
Performance and optimization CakeFest 2014
 
Road to CakePHP 3.0
Road to CakePHP 3.0Road to CakePHP 3.0
Road to CakePHP 3.0
 
Performance and optimization
Performance and optimizationPerformance and optimization
Performance and optimization
 
OWASP Top 10 2013
OWASP Top 10 2013OWASP Top 10 2013
OWASP Top 10 2013
 
CakePHP the yum & yuck
CakePHP the yum & yuckCakePHP the yum & yuck
CakePHP the yum & yuck
 
Introduction to Twig
Introduction to TwigIntroduction to Twig
Introduction to Twig
 
Owasp top 10
Owasp top 10Owasp top 10
Owasp top 10
 
Simple search with elastic search
Simple search with elastic searchSimple search with elastic search
Simple search with elastic search
 
Making the most of 2.2
Making the most of 2.2Making the most of 2.2
Making the most of 2.2
 
Intro to continuous integration
Intro to continuous integration Intro to continuous integration
Intro to continuous integration
 

Recently uploaded

Recently uploaded (20)

A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your Business
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of Brazil
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 

Ch ch-changes cake php2