diff --git a/assets/javascripts/views/pages/cakephp.coffee b/assets/javascripts/views/pages/cakephp.coffee
new file mode 100644
index 00000000..c54ba198
--- /dev/null
+++ b/assets/javascripts/views/pages/cakephp.coffee
@@ -0,0 +1,6 @@
+#= require views/pages/base
+
+class app.views.CakephpPage extends app.views.BasePage
+ prepare: ->
+ @highlightCode @findAllByTag('pre'), 'php'
+ return
diff --git a/assets/stylesheets/application-dark.css.scss b/assets/stylesheets/application-dark.css.scss
index 33c0ba6c..c9e466e9 100644
--- a/assets/stylesheets/application-dark.css.scss
+++ b/assets/stylesheets/application-dark.css.scss
@@ -33,6 +33,7 @@
'pages/apache',
'pages/bower',
'pages/c',
+ 'pages/cakephp',
'pages/chai',
'pages/clojure',
'pages/coffeescript',
diff --git a/assets/stylesheets/application.css.scss b/assets/stylesheets/application.css.scss
index a0caa437..66a0e359 100644
--- a/assets/stylesheets/application.css.scss
+++ b/assets/stylesheets/application.css.scss
@@ -33,6 +33,7 @@
'pages/apache',
'pages/bower',
'pages/c',
+ 'pages/cakephp',
'pages/chai',
'pages/clojure',
'pages/coffeescript',
diff --git a/assets/stylesheets/pages/_cakephp.scss b/assets/stylesheets/pages/_cakephp.scss
new file mode 100644
index 00000000..2e24da6f
--- /dev/null
+++ b/assets/stylesheets/pages/_cakephp.scss
@@ -0,0 +1,16 @@
+._cakephp {
+ h2 { @extend %block-heading; }
+
+ h3 { @extend %block-label, %label-blue; }
+
+ h3 > a { float: right; }
+
+ h3 > a,
+ span.label,
+ span.php-keyword1 {
+ font-weight: normal;
+ }
+
+ .tree > dd { margin-left: 0px; }
+ .list { margin-left: 20px; }
+}
diff --git a/lib/docs/filters/cakephp/clean_html.rb b/lib/docs/filters/cakephp/clean_html.rb
new file mode 100644
index 00000000..f6c20e17
--- /dev/null
+++ b/lib/docs/filters/cakephp/clean_html.rb
@@ -0,0 +1,59 @@
+module Docs
+ class Cakephp
+ class CleanHtmlFilter < Filter
+ def call
+ if root_page?
+ css('.section').remove
+ end
+
+ css('.breadcrumbs', '.info', 'a.permalink').remove
+
+ css('h1').drop(1).each do |node|
+ node.name = 'h2'
+ end
+
+ css('.property-name').each do |node|
+ node.name = 'h3'
+ end
+
+ # Move dummy anchor to method and property name
+ css('.method-detail').each do |node|
+ node.at_css('.method-name')['id'] = node.at_css('a')['id']
+ end
+ css('.property-detail').each do |node|
+ node.at_css('.property-name')['id'] = node['id']
+ node.remove_attribute('id')
+ end
+
+ # Break out source link to separate element
+ css('.method-name', '.property-name').each do |node|
+ source = node.at_css('a')
+ source.add_previous_sibling("#{source.content}")
+ source.content = 'source'
+ end
+
+ # These are missing in upstream documentation. Not sure why.
+ css('.section > h2').each do |node|
+ if node.content == "Method Detail"
+ node['id'] = 'methods'
+ end
+ if node.content == 'Properties summary'
+ node['id'] = 'properties'
+ end
+ end
+
+ css('.method-signature').each do |node|
+ node.name = 'pre'
+ node.content = node.content.strip
+ end
+
+ css('span.name > code').each do |node|
+ node.content = node.content.strip
+ end
+
+ # Pages don't share a nice common base css tag.
+ doc.children
+ end
+ end
+ end
+end
diff --git a/lib/docs/filters/cakephp/entries.rb b/lib/docs/filters/cakephp/entries.rb
new file mode 100644
index 00000000..56ca78dc
--- /dev/null
+++ b/lib/docs/filters/cakephp/entries.rb
@@ -0,0 +1,55 @@
+module Docs
+ class Cakephp
+ class EntriesFilter < Docs::EntriesFilter
+ INCLUDE_PAGE_TYPES = {
+ 'class' => true,
+ 'function' => true,
+ 'namespace' => false,
+ }
+
+ def get_page_type
+ page_type = slug.split('-')[0]
+ end
+
+ def include_default_entry?
+ INCLUDE_PAGE_TYPES[get_page_type]
+ end
+
+ def get_name
+ case get_page_type
+ when 'class'
+ slug.split('.').last
+ when 'function'
+ at_css('h1').content.split(' ')[1]
+ end
+ end
+
+ def get_type
+ case get_page_type
+ when 'class'
+ slug.split('.')[1..-2].join('\\')
+ when 'function'
+ 'Global Functions'
+ end
+ end
+
+ def additional_entries
+ entries = []
+ if get_page_type == 'class'
+ css('.method-name').each do |node|
+ name = get_name + '::' + node.at_css('.name').content.strip + '()'
+ id = node['id']
+ entries << [name, id, get_type]
+ end
+ css('.property-name').each do |node|
+ name = get_name + '::' + node.at_css('.name').content.strip
+ id = node['id']
+ entries << [name, id, get_type]
+ end
+ end
+ entries
+ end
+
+ end
+ end
+end
diff --git a/lib/docs/scrapers/cakephp.rb b/lib/docs/scrapers/cakephp.rb
new file mode 100644
index 00000000..24dbb4dc
--- /dev/null
+++ b/lib/docs/scrapers/cakephp.rb
@@ -0,0 +1,26 @@
+module Docs
+ class Cakephp < FileScraper
+ self.name = 'CakePHP'
+ self.type = 'cakephp'
+ self.version = '3.1'
+ self.dir = ''
+ self.base_url = "http://api.cakephp.org/#{version}/"
+ self.root_path = 'index.html'
+ self.links = {
+ home: 'http://cakephp.org/',
+ code: 'https://github.com/cakephp/cakephp'
+ }
+
+ html_filters.push 'cakephp/clean_html', 'cakephp/entries'
+
+ options[:container] = '#right.columns.nine'
+
+ # CakePHP docs include full source code. Ignore it.
+ options[:skip_patterns] = [/\Asource-/]
+
+ options[:attribution] = <<-HTML
+ © 2005–2015 The Cake Software Foundation, Inc.
+ Licensed under the MIT License.
+ HTML
+ end
+end
diff --git a/public/icons/docs/cakephp/16.png b/public/icons/docs/cakephp/16.png
new file mode 100644
index 00000000..41e8d0aa
Binary files /dev/null and b/public/icons/docs/cakephp/16.png differ
diff --git a/public/icons/docs/cakephp/16@2x.png b/public/icons/docs/cakephp/16@2x.png
new file mode 100644
index 00000000..d4c668e5
Binary files /dev/null and b/public/icons/docs/cakephp/16@2x.png differ
diff --git a/public/icons/docs/cakephp/SOURCE b/public/icons/docs/cakephp/SOURCE
new file mode 100644
index 00000000..2e3167d0
--- /dev/null
+++ b/public/icons/docs/cakephp/SOURCE
@@ -0,0 +1 @@
+http://cakephp.org/pages/logos