How To Setup CakePHP DataSource For Solr?

Imagine that you have millions of data and your SQL database is not optimized enough to handle them, then “Solr” is your best data source. Apache Solr is a fast search platform. It’s major features include full-text search faceted search, dynamic clustering, database integration, rich document handling. Solr is highly scalable and it is the most popular enterprise search engine.

This document will guide you through DataSource setup for Solr in CakePHP. Set-up the Solr DataSource in CakePHP and query Solr with your CakePHP model “find” function, just similar to querying any other SQL database.

/app/Config/database.php:

Configuring your the DataSource for Solr database connection:

  • host: Solr server address.
  • port: Solr server port.
  • datasource: This should match with your DataSource at /app/Model/Datasource/SolrSource.php

[php]class DATABASE_CONFIG {
public $solr = array(
‘datasource’ => ‘SolrSource’,
‘host’ => ‘192.168.2.131’,
‘port’ => ‘9983’,
‘path’ => ‘/solr/’
);
}[/php]

/app/Model/Solr.php:

Use the database config in your models like:

[php]class Solr extends AppModel {
 public $useTable = false;
 public $useDbConfig = ‘solr’;
 }[/php]

/app/Model/Datasource/SolrSource.php:

Below code describes only the most required functions.

  • You can find other required functions at http://book.cakephp.org/2.0/en/models/datasources.html
    Like: calculate($model, $func, $params) and others create(), update(), delete().
  • Below DataSource only implements read() function.
  • Create a file called SolrSource.php and use below code:

[php]App::uses(‘HttpSocket’, ‘Network/Http’);
require_once($_SERVER[‘DOCUMENT_ROOT’].’/root_folder/app/Vendor/Apache/Solr/Service.php’);
class SolrSource extends DataSource {

protected $_schema = array();
protected $_host;
protected $_port;

public function __construct($config){
parent::__construct($config);
$this->Http = new HttpSocket();

$this->host = $config[‘host’];
$this->port = $config[‘port’];
$this->_schema = $config[‘path’];

$this->solr=new Apache_Solr_Service($this->host, $this->port, $this->_schema);
}

public function read(Model $model, $queryData = array(), $recursive = null) {
$results = array();
$query = $queryData[‘conditions’][‘solr_query’];
if (Configure::read(‘log_solr_queries’) === true) {
CakeLog::write(‘debug’, $query); /* Logs the solr query in app/tmp/logs/debug.log file */
}

try {
$solr_docs = $this->solr->search($query, $queryData[‘offset’], $queryData[‘limit’], array(‘sort’ => $queryData[‘order’]));
} catch (Exception $e) {
CakeLog::write(‘error’, $e->getMessage()); /* Logs the solr errors message in app/tmp/logs/error.log file */
CakeLog::write(‘error’, $query); /* Logs the solr query in app/tmp/logs/error.log file */
}
$model->params = $solr_docs->responseHeader->params;
$model->numFound = $solr_docs->response->numFound;
$docs = $solr_docs->response->docs;
foreach ($docs as $doc) {
$document = array();
foreach ($doc as $fieldName => $fieldValue) {
$document[$fieldName] = $fieldValue;
}
$results[] = $document;
}
return array($model->alias => $results);
}
}[/php]

/app/Controller/UsersController.php:

Getting data from Solr server by using above SolrSource.

[php]App::uses(‘AppController’, ‘Controller’);
class UsersController extends AppController {

public $name = ‘Users’; //Controller name
public $uses = array(‘Solr’); //Model name

function beforeFilter(){
parent::beforeFilter();
$this->Auth->allow(‘index’);
}

public function index(){
$cond = "active:1";
$sort = "timestamp desc";

$params = array(
‘conditions’ =>array(
‘solr_query’ => $cond
),
‘order’ => $sort,
‘offset’ => 0,
‘limit’ => 1
);

$result = $this->Solr->find(‘all’, $params);
$this->layout = ‘ajax’;
header(‘Content-Type: application/json; charset=utf-8’); /* To send response in json format */
echo json_encode($result);
die;
}
}[/php]

See Also : How to use ‘neighbors’ with ‘find’ method

Debugging:

The above code has been tested and validated with CakePHP 2.2.3, PHP 5.3.1 .
Incase you face any problems:

  • First check the DataSource configuration in /app/Config/database.php.
  • Check /app/Model/Solr.php for this line: public $useDbConfig = ‘solr’;
  • Make sure Solr Service Vendor loaded in /app/Model/Datasource/SolrSource.php.
  • Check the path is correct for the Solr vendor.

Hope you liked this. Let me know if you want to add anything?

Creating A Custom Handler Session In CakePHP 2.x

Sessions manage and customization is very easy in CakePHP. Setting and configuration come out of the box so basically you don’t need to configure at all. But still at some point we need customization like, if we need some changes in php.ini or want to store session in a different place.

You can manage session, write custom handler, add option to save on different places, override php.ini settings.

Write Your Own Custom Handler For Sessions in Cake:

To Save Session With Setting in php.ini:

Configure::write('Session', array(
'defaults' => 'php'
));

This is the default setting that comes out of the box by CakePHP.

To Save Session Inside Cake tmp Folder:

Configure::write('Session', array(
'defaults' => 'cake'
));

This is required in a host where it does not allow you to write outside your home directory.

To Save Session in Database:

Configure::write('Session', array(
'defaults' => 'database'
));

This uses a built-in database defaults. It stores session in ‘cake_sessions’ table.
So you need to create a table for this:

CREATE TABLE `cake_sessions` (
`id` varchar(255) NOT NULL DEFAULT '',
`data` text,
`expires` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
);

But you can specify you own session handler to store session using a different model:

Configure::write('Session', array(
'defaults' => 'database',
'handler' => array(
'model' => 'MyCakeSession'
)
));

Create ‘MyCakeSession’ model at app/Model/MyCakeSession.php  And create ‘my_cake_sessions’ table:

CREATE TABLE `my_cake_sessions` (
`id` varchar(255) NOT NULL DEFAULT '',
`data` text,
`expires` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
);

This will save session ‘my_cake_sessions’ using MyCakeSession model.

To Save Session in Cake Cache:

Configure::write('Session', array(
'defaults' => 'database'
));

Making Session Persist Across All Sub-Domains:

  • Add below in bootstrap:
    ini_set(‘session.cookie_domain’, env(‘HTTP_BASE’));
  • This changes the default, that only the domain generating a session can access, to all sub-domains.
  • You don’t need to make core Security.level to low or medium.
  • You can also use php, cake, database or cache in core Session default to persist session in all sub-domains.

Troubleshoot:

  • When you test with the session management you might get error: “cakephp 404 The request has been black-holed”.
  • Try clear tmp/cache/, tmp/cache/models, tmp/cache/persistent, tmp/sessions.
  • Try clear browser cookie and cache.
  • Check core Session configurations.

Always try to clear browser cookie, cache before doing changes in core Session or php.ini configuration.

Other Session configuration that can be done are cookie name, timeout, cookieTimeout, checkAgent, autoRegenerate, and other ini values like cookie_secure, cookie_path, cookie_httponly.

See Also : How to migrate CakePHP 1.x to 2.x

Like this blog? I’d love to hear about your thoughts on this. Thanks for sharing your comments.

Containable Behavior in CakePHP

When we are going to retrieve records of (user) using User model, we can get the associated model’s record at the same time. That might not require at some point. To avoid this, CakePHP provides the bindModel/unbindModel methods. But this is not be a good practice. You can streamline your operation using the containable behavior. The performance and the speed will increased as well. It will mostly reduce the joining of tables.

Usage & Examples:

class User extends AppModel {
     public $actsAs = array('Containable');
   }

Where “User” is the model for which you are adding the containable behavior.

You can also do the following on the fly:

$this->User->Behaviors->load(‘Containable’);

Operations:

Without the use of Containable

$this->User->find('all');
  Here User model has hasMany relation with the Comment.
  [0] => Array
        (
            [User] => Array
                (
                    [id] => 1
                    [title] => First article1
                    [content] => aaa1
                    [created] => 2008-05-17 00:00:00
                )
            [Comment] => Array
                ( [0] => Array
          (
            [id] => 1
            [User_id] => 1
            [author] => Daniel1
            [email] => dan@example.com1
            [website] => http://example.com1
            [comment] => First comment1
            [created] => 2008-05-17 00:00:00
          )
        [1] => Array
          (
            [id] => 2
            [User_id] => 1
            [author] => Sam1
            [email] => sam@example.net1
            [website] => http://example.net1
            [comment] => Second comment1
            [created] => 2008-05-10 00:00:00
          )
      )
  )
  [1] => Array
  (
    [User] => Array
      (...

Using Containable:

Case 1: If we need only User data.

$this->User->contain();
      $this->User->find('all');
  OR
  $this->User->find('all', array('contain' => false));
  Out Put:
  [0] => Array
        (
            [User] => Array
                (
                    [id] => 1
                    [title] => First article1
                    [content] => aaa1
                    [created] => 2008-05-17 00:00:00
                )
        )
       [1] => Array
        (
            [User] => Array
                (
                    [id] => 2
                    [title] => Second article1
                    [content] => bbb1
                    [created] => 2008-05-10 00:00:00
                )
        )
  Case 2: With complex associations
       $this->User->contain('Comment.author');
           $this->User->find('all');
 
           // or..
 
           $this->User->find('all', array('contain' => 'Comment.author'));
  Out put:
  [0] => Array
        (
            [User] => Array
                (
                    [id] => 1
                    [title] => First article1
                    [content] => aaa1
                    [created] => 2008-05-17 00:00:00
                )
            [Comment] => Array
                (
                    [0] => Array
                        (
                            [author] => Daniel1
                            [User_id] => 1
                        )
                    [1] => Array
                        (
                            [author] => Sam1
                            [User_id] => 1
                        )
                )
        )
 
   $this->User->find('all', array('contain' => 'Comment.author = "Daniel1"'));
 
    Out put:
  [0] => Array
        (
            [User] => Array
                (
                    [id] => 1
                    [title] => First article1
                    [content] => aaa1
                    [created] => 2008-05-17 00:00:00
                )
            [Comment] => Array
                (
                    [0] => Array
                        (
                            [id] => 1
                            [post_id] => 1
                            [author] => Daniel1
                            [email] => dan@example.com1
                            [website] => http://example.com1
                            [comment] => First comment1
                            [created] => 2008-05-11 00:00:00
                        )
                )
        )
  [1] => Array
        (
            [User] => Array
                (
                    [id] => 2
                    [title] => Second article2
                    [content] => bbb2
                    [created] => 2008-05-22 00:00:00
                )
            [Comment] => Array
                (
                )
        )

The gray area showing that the User data always returned irrespective of the “Comment”.

Pagination Using Containable:

Including the ‘contain’ parameter in the $paginate property we can achieve find(‘count’)
and find(‘all’) on the model. This is a most valuable feature of CakePHP.

$this->paginate['User'] = array(
    'contain' => array('Comment', 'Tag'),
    'order' => 'User.name'
  );
  $users = $this->paginate('User');

If you are searching for PHP or CakePHP developers, then we are the ideal and cost savvy option for you.

Like this blog? I’d love to hear about your thoughts on this. Thanks for sharing your comments.

Hash Class: Makes CakePHP Coding easier!

Hash is a predefined class provided by CakePHP. It is used for array manipulation such as inserting an element to an array, remove an element from an array, sort an array, extract part of a large array, filter the non empty elements, rearrange the whole array, which makes the code more optimized and understandable. So it makes CakePHP easier and flexible to use. Because most of the operations like find, insert, update in CakePHP returns/takes array as output/input.

Hash provides an improved interface, more consistent and predictable set of features over Set. While it lacks the spotty support for pseudo XPath, its more fully featured dot notation provides similar features in a more consistent implementation.

Operations performed by Hash class:

  • extract()
  • combine()
  • filter()
  • check()
  • insert()
  • remove()
  • sort()
  • and many more…

Some Important Tips:

{n} – Match any numeric key.
{s} – Match any string value and numeric string values.
[id] – Matches elements with a given array key.
[id=2] – Matches elements with id equal to 2.
[id!=2] – Matches elements with id not equal to 2.
[id<=2] – Matches elements with id less than or equal to 2.

– Matches elements that have values matching the regular expression inside.

  • Hash::extract(array $data, $path):

Retrieve required data from array. You do not have to loop through the array.

Ex: // Common Usage:

$users = $this->User->find("all");
 $results = Hash::extract($user, '{n}.User.id');
 // $results equals:
 // array(1,2,3,4,5,...);
  • Hash::insert(array $data, $path, $values = null):

Insert sub-array’s into the original array.

Ex:

$temp = array(
 'page' => array('name' => 'page')
);
$result = Hash::insert($temp, 'file', array('name' => 'files'));
// $result now looks like:
Array
(
 [page] => Array
 (
 [name] => page
 )
 [file] => Array
 (
 [name] => files
 )
)
  • Hash::remove(array $data,  $path = null):
Remove data from any path specified.

EX:

$arr_test = array(
 'page' => array('name' => 'page'),
 'file' => array('name' => 'files')
);
$result = Hash::remove($arr_test, 'file');
/* $result now looks like:
 Array
 (
 [page] => Array
 (
 [name] => page
 )
 
)
*/
  • Hash::combine(array $data$keyPath = null$valuePath = null$groupPath = null)

Combine the results to form a new array of expected result. Helpful in case, where we are displaying data in the form of select box. Like categories, states, city etc. We don’t have to retrieve the data separately. We can find the required data from the original result set retrieved, containing the information..

Ex:

$arr_test = array(
 array(
 'User' => array(
 'id' => 2,
 'group_id' => 1,
 'Data' => array(
 'user' => 'John.doe',
 'name' => 'Matt Lee'
 )
 )
 ),
 array(
 'User' => array(
 'id' => 14,
 'group_id' => 2,
 'Data' => array(
 'user' => 'phpunt',
 'name' => 'Jack'
 )
 )
 ),
);
 
$result = Hash::combine($arr_test, '{n}.User.id', '{n}.User.Data');
/* $result now looks like below:
 Array
 (
 [2] => Array
 (
 [user] => John.doe
 [name] => Matt Lee
 )
 [14] => Array
 (
 [user] => phpunt
 [name] => Jack
 )
 )
*/
  • Hash::check(array $datastring $path = null)
    Check whether an element exists in the array or not.

Ex:

$set = array(
 'My Index' => array('First' => 'The first item1')
);
$result = Hash::check($set, 'My Index.First');
// $result == True
  • Hash::filter(array $data$callback = array(‘Hash ‘‘Filter’)):
Keep only non-empty elements and filter the empty elements.
Ex:
$data_arr = array(
 '0',
 false,
 true,
 0,
 array('test', 'is you own', false)
);
$result = Hash::filter($data_arr);
 
/* Out put:
 Array (
 [0] => 0
 [2] => true
 [3] => 0
 [4] => Array
 (
 [0] => one thing
 [2] => is you own
 )
 )
*/
  • Hash::sort(array $data$path$dir$type = ‘regular’)

Sort an array according to the path, direction and type provided.

Ex:

$arr_test = array(
 0 => array('Person' => array('name' => 'Jeff1')),
 1 => array('Shirt' => array('color' => 'black1'))
);
$result = Hash::sort($arr_test, '{n}.Person.name', 'asc');
/* $result now looks like:
 Array
 (
 [0] => Array
 (
 [Shirt] => Array
 (
 [color] => black1
 )
 )
 [1] => Array
 (
 [Person] => Array
 (
 [name] => Jeff1
 )
 )
 )
*/

$type can be of the following type:

regular
numeric
string
natural(ex. Will sort fooo10 below fooo2 as an example)

$dirc can be of two type asc & desc

For more information refer: http://book.cakephp.org/2.0/en/core-utility-libraries/hash.html

However if you want you can hire or get free consultation from our experienced CakePHP developers.

Read More: Password Hashing API in PHP

Have I missed out anything? Comment at end of this topic.

CakePHP: How To Use ‘neighbors’ With ‘find’ Method

CakePHP ‘find’ method makes it easier to retrieve data from database. The ‘find’ method can be used to construct anything from extremely simple queries to more complex ones without writing much code. This method can handle most SQL type requests and can be extended for more specific SQL queries.  I will walk you through the below example about the basics of working with the ‘find’  method

Here Are Some Inbuilt Types in CakePHP

  1. $this->Model->find(‘all’,$condition);
  2. $this->Model->find(‘first’,$condition);
  3. $this->Model->find(‘count’,$condition);
  4. $this->Model->find(‘list’,$condition);
  5. $this->Model->find(‘neighbors’,$condition);
  6. $this->Model->find(‘threaded’,$condition);

First four types are the most commonly used in CakePHP
Now, let’s take a look at an example of ‘neighbors’ type

Example

Let’s assume QuizQuestion is your model and you want to fetch the previous and next entries

Your Controller/action will look like,

public function getNeighbors($id){
 
$this->QuizQuestion->id = $id;
 
$neighbors = $this->QuizQuestion->find('neighbors',array('fields'=>array('id','question_no','description')));
}

A couple of queries will be generated in SQL as,

Query: SELECT 'QuizQuestion'.'id', 'QuizQuestion'.'question_no', 'QuizQuestion'.'description',
'QuizQuestion'.'id' FROM 'quiz_questions' WHERE 'QuizQuestion'.'id' < 38   ORDER BY
'QuizQuestion'.'id' DESC  LIMIT 1
Query: SELECT 'QuizQuestion'.'id', 'QuizQuestion'.'question_no', 'QuizQuestion'.'description',
'QuizQuestion'.'id' FROM 'quiz_questions' WHERE 'QuizQuestion'.'id' > 38   ORDER BY
'QuizQuestion'.'id' ASC  LIMIT 1

Here’s the output

Array
(
[prev] => Array
(
[QuizQuestion] => Array
(
[id] => 37
[question_no] => 1
[description] => Mathematics
)
 
)
[next] => Array
(
[QuizQuestion] => Array
(
[id] => 39
[question_no] => 3
[description] => Mathematics
)
 
)
 
)

Voila! Using the result keys ‘prev’ and ‘next’ you can view the results the way you want.

The 10th Best CakePHP Web-App Development Company in The World

Today, we are thrilled to announce that Andolasoft is named at #10 in the Top 10 CakePHP Development Companies by bestwebdesignagencies.com.

We pledge this success to our customers for their continuous support which has brought us such laurels. We are pleased that our team of expert CakePHP developers, project management, and testing have done their job to perfection yet again.

Our Comprehensive Range of CakePHP Development Services

  • Custom PHP Web Development
  • PHP-Based CMS Development
  • PHP-Based eCommerce Development
  • PHP Migration Services
  • PHP Web-App Maintenance Services
  • PHP API & Plugin Development
  • PHP-Based Web Product Development

Key Solutions We Provide to Mitigate Customer Challenges

  • We offer full-stack CakePHP developers who create a seamless integration of front-end and back-end services to deliver a consistent user experience
  • Our expert team of developers provide high-level of customization both in terms of user-experience, user-interface and app-functionalities.
  • We employ the highest level of security measures to ensure our client’s and end-users’ data remain secure.
  • We follow an agile development process to craft PHP solutions in an iterative and incremental process.
  • Our team members are well-versed in using light-weight plugins to optimize web-performance.
  • Customers can collaborate with our team members and project managers on Orangescrum project collaboration tools.
  • We offer the quickest turnaround customer support during all stages of product development.

Why Brand Around the World Choose Andolasoft for CakePHP Web-App Development

Client-Friendly Approach

Our development team and project managers are approachable and easy-to-talk-to. They keep the atmosphere light and friendly when communicating with clients on project requirements.

Latest Tools and Technologies

Our team always keeps themselves updated with the latest tools and technologies giving our customers the winning-edge by crafting a solution that is more updated, secure and optimized.

Agile Development Model

We follow Agile methodology to develop solutions in an interactive and incremental manner which enables our team members to keep publishing various modules of the product faster.

Never miss an update from us. Join 10,000+ marketers and leaders.

Why parallax scrolling is in trend?

It keeps our development process open to new changes and modifications.

Comfortable to work in your Time zone

We have dedicated developers who can work on your time zone and develop solutions exclusively for our clients.

Maintenance & QA

Out QA cover 100% of the modules, features and functionalities developed to ensure the credibility of the product developed. We leave no stone unturned and ensure that the product developed meets your business and functional requirements.

Quickest Turnaround Customer Support

Andolasoft has the quickest turnaround customer support. We reach out to our customers faster to resolve their queries and issues during all stages of our partnership.

No Hidden Cost

We charge only for the services we offer as defined while signing the NDA. We don’t surprise you with any hidden cost after delivery of your project.

Flexible Hiring Models

Our customers have the option to work with us by hiring our team of developers and designers on a per-hour basis or hire dedicated developers who will work exclusively on customer projects in their time zone.

Track Your Projects Through PM Tool

You can track the progress of your projects using Orangescrum PM tool.

Are you looking for a CakePHP developer

Contact Us

We keep our customers in the loop and keep updating them at every step of the development lifecycle.

What Factors Helped Us:

      • The development of CakePHP web-apps based on MVC architecture
      • Re-usability of code to develop robust apps in less time
      • Rapid web-app development with Agile methodology
      • Search engine friendly CakePHP apps
      • Secure apps with a logical separation of data, business logic, and design
      • Strong security measures to keep application data secured
      • Social Media, Payment gateway and other API integration to our web-apps
      • Best Practices Followed
      • On-time delivery
      • Faster Communication
      • Quick turnaround Support

Conclusion

The bestwebdesignagencies.com is an autonomous body that identifies and lists out the best design and development companies in the world. The purpose is to help customers to find the right ones in the industry. They adopt a stringent evaluation process to determine the quality of work delivered by each company to their customers’ satisfaction.