This is a pretty simple task with the orm. As @ndm mentioned in the comments, you can do this with a left join which is the default of the belongsTo association.
In the BooksTable make sure the association is added in the initialization method:
public function initialize(array $config)
{
parent::initialize($config);
$this->setTable('books');
$this->setDisplayField('id');
$this->setPrimaryKey('id');
$this->belongsTo('Authors', [
'foreignKey' => 'author_id'
]);
}
In your Books controller (if that is the controller you are doing things in):
$books_without_authors = $this->Books
->find()
->contain(['Authors'])
->where(['Authors.id IS NULL'])
->all();
$books_with_authors = $this->Books
->find()
->contain(['Authors'])
->where(['Authors.id IS NOT NULL'])
->all();
If you are going to be doing this from multiple controllers then the DRY way to do it is as an association:
public function initialize(array $config)
{
parent::initialize($config);
$this->setTable('books');
$this->setDisplayField('id');
$this->setPrimaryKey('id');
$this->belongsTo('Authors', [
'foreignKey' => 'author_id'
]);
$this->belongsTo('WithAuthors', [
'className' => 'Authors',
'foreignKey' => 'author_id',
'joinType' => 'INNER'
]);
$this->belongsTo('WithoutAuthors', [
'className' => 'Authors',
'foreignKey' => 'author_id',
'conditions' => ['Authors.id IS NULL']
]);
}
You can then call these in your controller
$with_authors = $this->Books
->find()
->contains(['WithAuthors'])
->all();
$without_authors = $this->Books
->find()
->contains(['WithoutAuthors'])
->all();