Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2a519a4
sample/PhotoAlbum - fix parsing for cloudinary created_at (ISO-8601)
m0she Oct 29, 2013
dae0ba1
php framework - Use DIRECTORY_SEPARATOR
m0she Nov 23, 2013
4344988
PhotoAlbum (non cake) - use cloudinary_js_config
m0she Nov 21, 2013
ee21e45
cake - Add freshly baked PhotoAlbumCake app and CloudinaryCake plugin
m0she Nov 6, 2013
dbf1258
php framework - cloudinary_url supports cloudinary identifier as source
m0she Nov 22, 2013
ca200e3
php framework - add extended_identifier to PreloadedFile
m0she Nov 23, 2013
ca5aba6
cake_plugin - add CloudinaryBehavior
m0she Nov 20, 2013
b9ec83e
cake_plugin - CloudinaryBehavior change model's defaults
m0she Nov 24, 2013
358399b
cake_plugin - use extended_identifier (from future 1.0.8) php framework
m0she Nov 23, 2013
ed01cfd
cake_plugin - add CloudinaryHelper
m0she Nov 21, 2013
daa260c
CloudinaryField - move from cake_plugin to src
m0she Nov 24, 2013
c0beff9
tests - add CloudinaryFieldTest [incomplete]
m0she Nov 25, 2013
7b0651c
PhotoAlbumCake - Setup private config
m0she Nov 6, 2013
59d3ae4
PhotoAlbumCake - bake all photo
m0she Nov 6, 2013
e3f9664
PhotoAlbumCake - Add Cloudinary support to photo admin actions
m0she Nov 21, 2013
e39e7fd
PhotoAlbumCake - Replace FormHelper with CloudinaryHelper
m0she Dec 5, 2013
d1b24e3
cake_plugin - better loading mechanism
m0she Dec 5, 2013
abc294b
Cake - Create documentations
m0she Dec 5, 2013
2e68039
PhotoAlbumCake - Add list_photos action/view
m0she Dec 7, 2013
3199ea7
php framework - Support folder in identifier
m0she Dec 10, 2013
dc9474d
cake_plugin - support cloudinary options for direct_upload
m0she Dec 10, 2013
f1de541
PhotoAlbumCake - added upload
m0she Dec 7, 2013
1e14481
PhotoAlbumCake - wire up together and fixes
m0she Dec 10, 2013
7c3a1de
PhotoAlbumCake - document
m0she Dec 10, 2013
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1 @@
.project
samples/PhotoAlbumCake/Config/private.php
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ For PHP, Cloudinary provides an extension for simplifying the integration even f
![](http://res.cloudinary.com/cloudinary/image/upload/see_more_bullet.png) **Take a look at our [Getting started guide for PHP](http://cloudinary.com/documentation/php_integration#getting_started_guide)**.


## CakePHP ##
Special support to the cake PHP is included. You can access the code, installation and usage information [in the `cake_plugin/CloudinaryCake/README.md` file](https://github.com/cloudinary/cloudinary_php/tree/master/cake_plugin/CloudinaryCake)

## Setup ######################################################################

Download cloudinary_php from [here](https://github.com/cloudinary/cloudinary_php/tarball/master)
Expand Down
Empty file.
26 changes: 26 additions & 0 deletions cake_plugin/CloudinaryCake/Config/bootstrap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

if (class_exists('\Cloudinary') && class_exists('\Cloudinary\Uploader') && class_exists('\CloudinaryField')) {
return 1;
}

$get_cloudinary_path = function() {
$autodetect = array(
realpath(implode(DS, array(dirname(__FILE__), '..', '..', '..', 'src'))),
realpath(implode(DS, array(dirname(__FILE__), '..', 'Lib', 'Cloudinary'))),
);
foreach ($autodetect as $path) {
$path .= DS;
if (file_exists($path . "Cloudinary.php")) {
return $path;
}
}
throw new \Exception("Couldn't guess cloudinary_php src path, please define CLOUDINARY_PATH");
};

if (!defined('CLOUDINARY_PATH')) {
define('CLOUDINARY_PATH', $get_cloudinary_path());
}
require_once CLOUDINARY_PATH . "Cloudinary.php";
require_once CLOUDINARY_PATH . "Uploader.php";
require_once CLOUDINARY_PATH . "CloudinaryField.php";
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

App::uses('AppController', 'Controller');

class CloudinaryCakeAppController extends AppController {

}
Empty file.
Empty file.
158 changes: 158 additions & 0 deletions cake_plugin/CloudinaryCake/Model/Behavior/CloudinaryBehavior.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
<?php

App::uses('ModelBehavior', 'Model');

class CloudinaryBehavior extends ModelBehavior {
public $settingsDefaults = array(
"fields" => array(),
"changeModelDefaults" => true
);

public function setup(Model $Model, $settings = array()) {
if (!isset($this->settings[$Model->alias])) {
$this->settings[$Model->alias] = $this->settingsDefaults;
}
$this->settings[$Model->alias] = array_merge(
$this->settings[$Model->alias], (array)$settings
);
if ($this->settings[$Model->alias]['changeModelDefaults']) {
$this->changeModelDefaults($Model);
}
}

/// Callbacks ///
public function afterFind(Model $Model, $results, $primary = false) {
$fieldNames = $this->relevantFields($Model);
if (!$fieldNames) {
return $results;
}

foreach ($results as &$result) {
foreach ($fieldNames as $fieldName) {
$this->updateCloudinaryField($Model, $fieldName, $result);
}
}
return $results;
}

public function beforeSave(Model $Model, $options = array()) {
foreach ($this->relevantFields($Model, $options) as $fieldName) {
$this->saveCloudinaryField($Model, $fieldName);
}
return true;
}

public function beforeValidate(Model $Model, $options = array()) {
foreach ($this->relevantFields($Model, $options) as $fieldName) {
$field = @$Model->data[$Model->alias][$fieldName];
if (is_string($field) && $field) {
if (!(new CloudinaryField($field))->verify()) {
$Model->invalidate($fieldName, "Bad cloudinary signature!");
return false;
}
}
}
return true;
}

/// Public Methods ///
public function cloudinaryFields(Model $Model) {
return $this->settings[$Model->alias]['fields'];
}

/// Private Methods ///
private function createCloudinaryField(Model $Model, $fieldName, $source=NULL) {
$source = $source ? $source : $Model->data;
return new CloudinaryField(isset($source[$Model->alias][$fieldName]) ?
$source[$Model->alias][$fieldName] : "");
}

private function updateCloudinaryField(Model $Model, $fieldName, &$data=NULL) {
$source =& $data ? $data : $Model->data;
if (isset($source[$Model->alias][$fieldName]) && $source[$Model->alias][$fieldName] instanceof CloudinaryField) {
return;
}
$source[$Model->alias][$fieldName] = $this->createCloudinaryField($Model, $fieldName, $source);
}

private function saveCloudinaryField(Model $Model, $fieldName) {
$field = @$Model->data[$Model->alias][$fieldName];
$ret = NULL;
if ($field instanceof CloudinaryField) {
return;
} elseif (!$field) {
$ret = new CloudinaryField();
} elseif (is_string($field)) {
$ret = new CloudinaryField($field);
// $ret->verify(); - Validate only in beforeValidate
} elseif (is_array($field) && isset($field['tmp_name'])) {
$ret = new CloudinaryField();
$ret->upload($field['tmp_name']);
} else {
// TODO - handle file object?
throw new \Exception("Couldn't save cloudinary field '" . $Model->alias . ":" . $fieldName .
"' - unknown input: " . gettype($field));
}
$Model->data[$Model->alias][$fieldName] = $ret;
}

private function relevantFields(Model $Model, $options = array()) {
$cloudinaryFields = $this->settings[$Model->alias]['fields'];
if (!(isset($options['fieldList']) && $options['fieldList'])) {
return $cloudinaryFields;
}
return array_intersect($cloudinaryFields, $options['fieldList']);
}

private static function modifyPropertyUsingForce($instance, $property, $newValue) {
if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
$myClassReflection = new ReflectionClass(get_class($instance));
$secret = $myClassReflection->getProperty($property);
$secret->setAccessible(true);
$secret->setValue($instance, $newValue);
}
}

private function changeModelDefaults(Model $Model) {
$schema = $Model->schema();
foreach ($this->relevantFields($Model) as $fieldName) {
$schema[$fieldName] = new CloneOnAccessArray($schema[$fieldName]);
$schema[$fieldName]['default'] = new CloudinaryField();
}
self::modifyPropertyUsingForce($Model, "_schema", $schema);
}
}

class CloneOnAccessArray extends ArrayObject {
public function offsetGet($offset) {
$ret = parent::offsetGet($offset);
return (is_object($ret)) ? clone $ret : $ret;
}
}

/*
Simplest usage:
Model:
class Photo extends AppModel {
public $actsAs = array('CloudinaryCake.Cloudinary' => array('fields' => array('cloudinaryIdentifier')));
}

Controller:
Find:
$photo = $this->Photo->find('first', $options); // returns CloudinaryField in

Modify:
$photo['Photo']['cloudinaryIdentifier'].upload($new_file);

Delete:
$photo['Photo']['cloudinaryIdentifier'].delete($new_file);

Save:
Photo->save($photo);

Save (from form):
Photo->save($this->request->data); // should work with file upload or identifier

* Validate identifier upon save
*
*/
Empty file.
7 changes: 7 additions & 0 deletions cake_plugin/CloudinaryCake/Model/CloudinaryCakeAppModel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

App::uses('AppModel', 'Model');

class CloudinaryCakeAppModel extends AppModel {

}
Empty file.
168 changes: 168 additions & 0 deletions cake_plugin/CloudinaryCake/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
Cloudinary CakePHP plugin
=========================

Cloudinary CakePHP plugin provides seemless integration of Cloudinary services with CakePHP framework for simple and efficient management of applications images

Explore the [PhotoAlbumCake sample](https://github.com/cloudinary/cloudinary_php/tree/master/samples/PhotoAlbumCake) for usage example.

## Requirements
* PHP 5.3 or higher
* CakePHP 2.x

## Installlation
### Manual
1. Create a CakePHP project
1. Download cloudinary\_php from [here](https://github.com/cloudinary/cloudinary_php/tarball/master)
1. Extract the cloudinary\_php archive into vendors library
1. Configure cloudinary
1. Environment variable - `export CLOUDINARY\_URL = "cloudinary://API_KEY:API_SECRET@CLOUD_NAME"` ([Check your settings in Cloudinary console](https://cloudinary.com/console))
1. Create `app/Config/private.php` using `vendor/cloudinary_php/samples/PhotoAlbumCake/Config/private.php.sample`
1. Load the cloudinary plugin by adding the following lines to `app/Config/bootstrap.php`:

// Load plugin
CakePlugin::load('CloudinaryCake', array('bootstrap' => true, 'routes' => false,
'path' => ROOT . DS 'vendor' . DS 'cloudinary_php' . DS . 'cake_plugin' . DS . 'CloudinaryCake' . DS));

// required when using `private.php` for cloudinary configuration
Configure::load('private');
\Cloudinary::config(Configure::read('cloudinary'));

### Composer
1. Create a new directory for myapp

mkdir myapp
cd myapp

1. Install CakePHP using composer ([based on CakePHP Cookbook](http://book.cakephp.org/2.0/en/installation/advanced-installation.html#installing-cakephp-with-composer)
1. Setup Composer and get CakePHP:

echo '{}' > composer.json
composer config vendor-dir Vendor
composer config repositories.0 pear 'http://pear.cakephp.org'
composer require 'pear-cakephp/cakephp:>=2.4.0'

1. Bake a new project

vendor/bin/cake bake project .

1. You may define `CAKE_CORE_INCLUDE_PATH` to a relative path as suggested in the cookbook by adding the following to `webroot/index.php`:

define(
'CAKE_CORE_INCLUDE_PATH',
ROOT . DS . APP_DIR . '/Vendor/pear-pear.cakephp.org/CakePHP'
)

1. Add the following lines to `Config/bootstrap.php`:

// Load composer autoload.
require APP . '/Vendor/autoload.php';

// Auto load CloudinaryCake plugin
\CloudinaryCakeLoader::load();


1. Install Cloudinary

composer require 'cloudinary/cloudinary_php:>=1.0.8'

1. Configure Cloudinary using the `CLOUDINARY_URL` environment variable, or the `Config/private.php` configuration file

## Usage

### CloudinaryBehavior
CloudinaryBehavior adds Cloudinary support for CakePHP Models. It helps storing references to cloudinary images in a simple text field of your model.

#### Setup
Assuming you have a `Photo` model with `cloudinaryIdentifier` text field for storing cloudinary images references - you can add the following code to your model

`Models/photo.php`:

[...]
class Photo extends AppModel {
public $actsAs = array('CloudinaryCake.Cloudinary' => array('fields' => array('cloudinaryIdentifier')));
[...]
}

#### Usage
This will allow you to access the `cloudinaryIdentifier` as a CloudinaryField. Here's a sample controller code -

`Controller/PhotosController.php`:

class PhotosController extends AppController {
[...]
// set the specified Photo's image to the default one
public function set_default_image($id) {
$options = array('conditions' => array('Photo.' . $this->Photo->primaryKey => $id));
$photo = $this->Photo->find('first', $options);

$photo['Photo']['cloudinaryIdentifier']->upload(DEFAULT_IMAGE_PATH);
$this->Photo->save($photo);
}

[...]
// Creates a new image from post data. Sets $image_url to the cloudinary url of the image with the given transformation.
public function add() {
$this->Photo->create();
$success = $this->Photo->save($this->request->data);
if ($success) {
$image_url = $this->Photo->data['Photo']['cloudinaryIdentifier']->url(array(
"width" => 100, "height" => 100, "crop" => "fill"));
}
$this->set('photo', $this->Photo->data);
}
[...]
}

### CloudinaryHelper
CloudinaryHelper is an extension of the CakePHP InputHelper. It can be used for loading cloudinary\_js, presenting images, creating forms with image inputs and more.

#### Setup
You can load CloudinaryHelper using two methods -

`Controller/PhotosController.php`:

[...]
class PhotosController extends AppController {
// Replace the FormHelper with CloudinaryHelper (recommended - accessible as $this->Form)
public $helpers = array('Html', 'Form' => array('className' => 'CloudinaryCake.Cloudinary'));

// Add CloudinaryHelper in addition to the default FormHelper (accessible as $this->Cloudinary instead of $this->Form)
//public $helpers = array('Html', 'Form', 'CloudinaryCake.Cloudinary');
[...]
}

#### Usage
You then can use it in any view of the controller:

`View/Layouts/default.ctp`:

[...]
<head>
[...]
# Include cloudinary_js dependencies (requires jQuery)
echo $this->Form->cloudinary_includes();
# Setup cloudinary_js using the current cloudinary_php configuration
echo cloudinary_js_config();
[...]
</head>
[...]

`View/Photos/add.ctp`:

[...]
<span><?php echo __('Current Photo:'); ?></span>
<?php echo $this->Form->cl_image_tag($photo['Photo']['cloudinaryIdentifier'],
array("width" => 60, "height" => 60, "crop" => "thumb", "gravity" => "face")); ?>

<?php echo $this->Form->create('Photo', array('type' => 'file')); ?>
<legend><?php echo __('Edit Photo'); ?></legend>
<?php
echo $this->Form->input('id');
# Backend upload:
echo $this->Form->input('cloudinaryIdentifier');
# Direct upload:
#echo $this->Form->input('cloudinaryIdentifier', array("type" => "direct_upload"));
?>
<?php echo $this->Form->end(__('Submit')); ?>
[...]

Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Loading