Im normal Fall wird die SEO-URL einer statischen Seite über den Namen/description gebildet. Ändert man nun den Namen der Seite, ändert sich auch der Link und damit könnten vorhandene eingetragene Links plötzlich nicht mehr funktionieren.
Um das zu verhindern, ist es praktisch der Namen für die SEO-URL unabhängig vom Namen erzeugen zu können. Da helfen die SEO Einstellungen im Punkt "SEO-Urls Shopseiten Template". Wir brauchen noch ein Freitextfeld mit dem DB-Spaltennamen "seourl". Nun ändern wir das Template:
{if $site.attributes.core.seourl}{$site.attributes.core.seourl}{else}{$site.description}{/if}
Wenn also dort im neuen Feld etwas angegeben ist, wird dieses verwendet und ansonsten weiterhin der Name. Das hat den Vorteil, dass man nur die Seite anpassen muss, die man umbenennen möchte und nicht jede.
Eine kleine Klasse, die ich mal für ein kleines Projekt geschrieben hatte, das mein Bruder brauchte (Verarbeitung und Katalogisierung von mehren 10.000en RTF-Dokumenten). Die Klasse liest alle Dateien eines Verzeichnisses und die alle seiner Unterverzeichnisse ein.
package de.hannespries.commons.io;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class RecursiveFileSeeker {
public static List<File> list(File folder, List<File> result, boolean allowFolders) {
return list(folder, result, allowFolders, new ArrayList<>());
}
public static List<File> list(File folder, List<File> result, boolean allowFolders, List<String> excludeDirnames) {
try {
if (!folder.isDirectory()) {
return result;
}
File[] files = folder.listFiles();
if (files != null) {
for (File file : files) {
if (file.isDirectory() && !excludeDirnames.contains(file.getName())) {
if (allowFolders) {
result.add(file);
}
if(!excludeDirnames.contains(file.getName())){
result = list(file, result, allowFolders, excludeDirnames);
}
} else {
result.add(file);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
Shopware bietet zwar ein Beispiel an, aber dieses Beispiel hat mich doch zu viel Zeit gekostet, bis es lief und die dort verlinkte ZIP-Datei ist leider auch nicht fehlerfrei. Deswegen habe ich mich mal daran gemacht eine eigene einfachere Beispiel Implementierung zu bauen, die als Vorlage mit viel Copy&Paste dienen kann.
Das Plugin
namespace HPrExampleRiskManagement;
use Shopware\Components\Plugin;
class HPrExampleRiskManagement extends Plugin{
//-- replace with our values --
private static $eventSuffixVarName = 'hpr_risk_example_event';
private static $eventSuffix = 'HPrRiskExample';
private static $extendFolder = 'hpr_risk_example';
private static $serviceName = 'hpr_risk_example.service';
//--
/**
* @return array
*/
public static function getSubscribedEvents(){
return [
'Enlight_Controller_Action_PostDispatchSecure_Backend_RiskManagement' => 'onRiskManagementBackend',
'Shopware_Modules_Admin_Execute_Risk_Rule_sRisk' . self::$eventSuffix => 'onRisk'
];
}
public function onRiskManagementBackend(\Enlight_Controller_ActionEventArgs $args){
$args->getSubject()->View()->addTemplateDir($this->getPath() . '/Resources/views');
if ($args->getSubject()->Request()->getActionName() == 'load') {
$args->getSubject()->View()->assign(self::$eventSuffixVarName, self::$eventSuffix);
$args->getSubject()->View()->extendsTemplate('backend/' . self::$extendFolder . '/store/risks.js');
}
}
/**
* @param \Enlight_Event_EventArgs $args
* @return bool
*/
public function onRisk(\Enlight_Event_EventArgs $args){
$result = false; //false == no risk
try{
$service = $this->container->get(self::$serviceName);
$result = $service->checkRule($args);
}
catch(\Exception $e){
}
return $result;
}
}
Ein Service
namespace HPrExampleRiskManagement\Components;
class RiskRuleService{
/**
* @param \Enlight_Event_EventArgs $args
* @return bool
*/
public function checkRule(\Enlight_Event_EventArgs $args){
return false;
}
}
Die services.xml
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="hpr_risk_example.service" class="HPrExampleRiskManagement\Components\RiskRuleService">
<tag name="service" />
</service>
</services>
</container>
Unsere risks.js (Pfad wie in Plugin)
//{extends file='parent:backend/risk_management/store/risks.js'}
//{block name="backend/risk_management/store/risk/data"}
// {$smarty.block.parent}
{ description: '{s name=risks_store/comboBox/HPrRiskExample}HPrExample Check{/s}', value: '{$hpr_risk_example_event}' },
//{/block}
An sich macht man nichts anderes als eine JSON Key-Value Liste zu erweitern und dort ein Event einzutragen, das eine Methode auslöst, die true (is a risk) oder false (is not a risk) zurück gibt. Diese Methode sollte nur als Facade für einen Service dienen, damit man die Logik schnell und einfach austauschen kann.
Das Plugin kann man dann eben noch um alles mögliche erweitern, wie Freitextfedler für Kunden und weitere Templates. Dann den Serive vollständig implementieren, nochmal was mit dem Snippet machen und man sollte seine RiskManagement-Rule haben.