Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
58 changes: 13 additions & 45 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,45 +1,13 @@
#--------------------------#
# Magento Default Files #
#--------------------------#

/PATCH_*.sh

/app/etc/local.xml

/media/*
!/media/.htaccess

!/media/customer
/media/customer/*
!/media/customer/.htaccess

!/media/dhl
/media/dhl/*
!/media/dhl/logo.jpg

!/media/downloadable
/media/downloadable/*
!/media/downloadable/.htaccess

!/media/xmlconnect
/media/xmlconnect/*

!/media/xmlconnect/custom
/media/xmlconnect/custom/*
!/media/xmlconnect/custom/ok.gif

!/media/xmlconnect/original
/media/xmlconnect/original/*
!/media/xmlconnect/original/ok.gif

!/media/xmlconnect/system
/media/xmlconnect/system/*
!/media/xmlconnect/system/ok.gif

/var/*
!/var/.htaccess

!/var/package
/var/package/*
!/var/package/*.xml

# Composer
/vendor/
.metadata
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.project
.buildpath
.idea/
89 changes: 89 additions & 0 deletions Adapter/Client.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php

namespace Develo\Typesense\Adapter;

use Devloops\Typesence\Client as TypeSenseClient;
use \Magento\Store\Model\ScopeInterface as ScopeConfig;
use \Magento\Framework\App\Config\ScopeConfigInterface;
use \Magento\Framework\Encryption\EncryptorInterface;

/**
* Class Client
*
* This class should replace the AlgoliaSearch\Client implementation
*
* @see \AlgoliaSearch\Client
* @package Develo\TypeSense\Service
*/
class Client
{

/**
* Config paths
*/
private const TYPESENSE_API_KEY = 'typesense_general/settings/admin_api_key';
private const TYPESENSE_NODES = 'typesense_general/settings/nodes';

/**
* @var TypeSenseClient
*/
private $typeSenseClient;

/**
* encryptor
*/
private $encryptor;

/**
* Initialise Typesense Client with Magento config
*/
public function __construct(
EncryptorInterface $encryptor,
ScopeConfigInterface $scopeConfig
)
{
$apiKey = $scopeConfig->getValue(SELF::TYPESENSE_API_KEY,ScopeConfig::SCOPE_STORE);
$apiKey = $encryptor->decrypt($apiKey);

$nodes = $scopeConfig->getValue(SELF::TYPESENSE_NODES,ScopeConfig::SCOPE_STORE);

$client = new TypeSenseClient(
[
"api_key" => $apiKey,
"nodes"=>
[
[
"host" => $nodes,
"port" => "443",
"protocol" => "https",
"api_key" => $apiKey
]
]
]
);

$this->typeSenseClient = $client;
}

/**
* @inheirtDoc
*/
public function deleteIndex($indexName)
{
return $this->typeSenseClient->collections[$indexName]->delete();
}

/**
* @inheirtDoc
*/
public function addData($indexName, $data)
{
return $this->typeSenseClient->collections[$indexName]->documents->create_many($data, ['action' => 'upsert']);
}

public function getTypesenseClient(){
return $this->typeSenseClient;
}
}


35 changes: 35 additions & 0 deletions Model/Config/Source/TypeSenseIndexMethod.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace Develo\Typesense\Model\Config\Source;

/**
* Algolia custom sort order field
*/
class TypeSenseIndexMethod implements \Magento\Framework\Data\OptionSourceInterface
{
/**
* @var array
*/
private $methods = [
'typesense' => 'Typesense Only',
'typesense_algolia' => 'Both Typesense and Aglolia',
'algolia' => 'Algolia Only'
];

/**
* @return array
*/
public function toOptionArray()
{
$options = [];

foreach ($this->methods as $key => $value) {
$options[] = [
'value' => $key,
'label' => __($value),
];
}

return $options;
}
}
84 changes: 84 additions & 0 deletions Observer/ConfigChange.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php

namespace Develo\Typesense\Observer;

use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\Event\Observer as EventObserver;
use Magento\Framework\App\RequestInterface;
use \Develo\Typesense\Adapter\Client;
use Algolia\AlgoliaSearch\Helper\Data as AlgoliaHelper;

class ConfigChange implements ObserverInterface
{

/**
* @var RequestInterface
*/
private $request;

/**
* $var Client
*/
private $typesenseClient;

/**
* $var AlgoliaHelper
*/
private $algoliaHelper;

/**
* $var Devloops\Typesence\Collections
*/
private $typeSenseCollecitons;

/**
* ConfigChange constructor.
* @param RequestInterface $request
*/
public function __construct(
RequestInterface $request,
Client $client,
AlgoliaHelper $algoliaHelper
) {
$this->request = $request;
$this->typesenseClient = $client->getTypesenseClient();
$this->algoliaHelper = $algoliaHelper;
$this->typeSenseCollecitons = $this->typesenseClient->collections;
}

/**
* Creates Indexes in Typesense after credentials have been updated
*/
public function execute(EventObserver $observer)
{
$indexes = $this->algoliaHelper->getIndexDataByStoreIds();
unset($indexes[0]); //skip admin store

$existingCollections = $this->getExistingCollections();

foreach($indexes as $index){
if(!isset($existingCollections[$index["indexName"]."_products"])){
$this->typeSenseCollecitons->create(
[
'name' => $index["indexName"]."_products",
'fields' => [['name' => 'name','type' => 'string']]
]
);
}
}

return $this;
}

/**
* Gets existing collections from typesense
*/
private function getExistingCollections(){
$collections = $this->typeSenseCollecitons->retrieve();
$existingCollections =[];
foreach($collections as $collection) {
$existingCollections[$collection["name"]] = $collection;
}
return $existingCollections;
}
}
68 changes: 68 additions & 0 deletions Plugin/Backend/Algolia/AlgoliaSearch/Helper/AlgoliaHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php
/**
* Copyright © All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Develo\Typesense\Plugin\Backend\Algolia\AlgoliaSearch\Helper;

use \Magento\Framework\App\Config\ScopeConfigInterface;
use \Magento\Store\Model\ScopeInterface as ScopeConfig;
use \Develo\Typesense\Adapter\Client;

class AlgoliaHelper
{
private const TYPESENSE_INDEX_METHID = 'typesense_general/settings/index_method';

/**
* @var $scopeConfig
*/
protected $scopeConfig;

/**
* @var Client $typesenseClient
*/
protected $typesenseClient;

/**
* __construct
* @param Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
* @param Develo\TypeSense\Adapter\Client $client
*/
public function __construct(
ScopeConfigInterface $scopeConfig,
Client $client
) {
$this->typesenseClient = $client;
$this->scopeConfig = $scopeConfig;
}

/**
* Indexes data if config is set todo, will index into algolia or typesense or both
*/
public function aroundAddObjects(
\Algolia\AlgoliaSearch\Helper\AlgoliaHelper $subject,
\Closure $proceed,
$objects,
$indexName
) {
$result = [];
$indexMethod = $this->scopeConfig->getValue(SELF::TYPESENSE_INDEX_METHID,ScopeConfig::SCOPE_STORE);
switch ($indexMethod) {
case "algolia":
$result = $proceed();
break;
case "typesense_algolia":
$this->typesenseClient->addData($indexName, $objects);
$result = $proceed();
break;
case "typesense":
default:
$this->typesenseClient->addData($indexName,$objects);
break;
}

return $result;
}
}
24 changes: 24 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "develo/typesense",
"description": "A TypeSense adapter for Magento 2",
"type": "magento2-module",
"license": "OSL-3.0",
"require": {
"algolia/algoliasearch-magento-2": "^3.9",
"typesense/typesense-php": "^2.0"
},
"authors": [
{
"name": "Nathan McBride",
"email": "nathan@brideo.co.uk"
},
{
"name": "Luke Collymore",
"email": "luke@develodesign.co.uk"
}
],
"autoload": {
"files": ["registration.php"],
"psr-4": {"Develo\\Typesense\\": ""}
}
}
16 changes: 16 additions & 0 deletions etc/acl.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Acl/etc/acl.xsd">
<acl>
<resources>
<resource id="Magento_Backend::admin">
<resource id="Magento_Backend::stores">
<resource id="Magento_Backend::stores_settings">
<resource id="Magento_Config::config">
<resource id="Develo_Typesense::config_Develo_Typesense" title="general"/>
</resource>
</resource>
</resource>
</resource>
</resources>
</acl>
</config>
6 changes: 6 additions & 0 deletions etc/adminhtml/di.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Algolia\AlgoliaSearch\Helper\AlgoliaHelper">
<plugin name="Develo_Typesense_Plugin_Backend_Algolia_AlgoliaSearch_Helper_AlgoliaHelper" type="Develo\Typesense\Plugin\Backend\Algolia\AlgoliaSearch\Helper\AlgoliaHelper" sortOrder="10" disabled="false"/>
</type>
</config>
6 changes: 6 additions & 0 deletions etc/adminhtml/events.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="admin_system_config_changed_section_typesense_general">
<observer name="develo_typesense_admin_system_config_changed_section_typesense_general" instance="Develo\Typesense\Observer\ConfigChange"/>
</event>
</config>
Loading