help/developer/addon-storage-backend/index.html

3778 lines
109 KiB
HTML
Raw Permalink Normal View History

<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="Friendica is a decentralised communications platform that integrates social communication. Our platform links to independent social projects and corporate services.">
<meta name="author" content="The Friendica project">
<link rel="canonical" href="https://friendi.ca/developer/addon-storage-backend/">
<link rel="icon" href="../../assets/images/friendica-32.png">
<meta name="generator" content="mkdocs-1.3.0, mkdocs-material-8.3.8">
<title>Addon Storage Backend - Friendica documentation</title>
<link rel="stylesheet" href="../../assets/stylesheets/main.1d29e8d0.min.css">
<link rel="stylesheet" href="../../assets/stylesheets/palette.cbb835fc.min.css">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
<link rel="stylesheet" href="../../assets/stylesheets/friendica.css">
<script>__md_scope=new URL("../..",location),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
</head>
<body dir="ltr" data-md-color-scheme="" data-md-color-primary="none" data-md-color-accent="none">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#friendica-storage-backend-addon-development" class="md-skip">
Skip to content
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Header">
<a href="https://friendi.ca" title="Friendica documentation" class="md-header__button md-logo" aria-label="Friendica documentation" data-md-component="logo">
<img src="../../assets/images/friendica.svg" alt="logo">
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3V6m0 5h18v2H3v-2m0 5h18v2H3v-2Z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
Friendica documentation
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
Addon Storage Backend
</span>
</div>
</div>
</div>
<div class="md-header__option">
<div class="md-select">
<button class="md-header__button md-icon" aria-label="Select language">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="m12.87 15.07-2.54-2.51.03-.03A17.52 17.52 0 0 0 14.07 6H17V4h-7V2H8v2H1v2h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04M18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12m-2.62 7 1.62-4.33L19.12 17h-3.24Z"/></svg>
</button>
<div class="md-select__inner">
<ul class="md-select__list">
<li class="md-select__item">
<a href="./" hreflang="en" class="md-select__link">
English
</a>
</li>
<li class="md-select__item">
<a href="../../de/developer/addon-storage-backend/" hreflang="de" class="md-select__link">
Deutsch
</a>
</li>
</ul>
</div>
</div>
</div>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z"/></svg>
</label>
<nav class="md-search__options" aria-label="Search">
<a href="javascript:void(0)" class="md-search__icon md-icon" aria-label="Share" data-clipboard data-clipboard-text="" data-md-component="search-share" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7 0-.24-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9a3 3 0 0 0-3 3 3 3 0 0 0 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.15c-.05.21-.08.43-.08.66 0 1.61 1.31 2.91 2.92 2.91 1.61 0 2.92-1.3 2.92-2.91A2.92 2.92 0 0 0 18 16.08Z"/></svg>
</a>
<button type="reset" class="md-search__icon md-icon" aria-label="Clear" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41Z"/></svg>
</button>
</nav>
<div class="md-search__suggest" data-md-component="search-suggest"></div>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initializing search
</div>
<ol class="md-search-result__list"></ol>
</div>
</div>
</div>
</div>
</div>
<div class="md-header__source">
<a href="https://github.com/friendica/friendica" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><!--! Font Awesome Free 6.1.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc.--><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg>
</div>
<div class="md-source__repository">
friendica/friendica
</div>
</a>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<nav class="md-tabs" aria-label="Tabs" data-md-component="tabs">
<div class="md-tabs__inner md-grid">
<ul class="md-tabs__list">
<li class="md-tabs__item">
<a href="../.." class="md-tabs__link">
Home
</a>
</li>
<li class="md-tabs__item">
<a href="../../user/account-basics/" class="md-tabs__link">
User
</a>
</li>
<li class="md-tabs__item">
<a href="../../admin/install/" class="md-tabs__link">
Admin
</a>
</li>
<li class="md-tabs__item">
<a href="../" class="md-tabs__link md-tabs__link--active">
Developer
</a>
</li>
<li class="md-tabs__item">
<a href="../../bugs-and-issues/" class="md-tabs__link">
Bugs and Issues
</a>
</li>
</ul>
</div>
</nav>
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary md-nav--lifted" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href="https://friendi.ca" title="Friendica documentation" class="md-nav__button md-logo" aria-label="Friendica documentation" data-md-component="logo">
<img src="../../assets/images/friendica.svg" alt="logo">
</a>
Friendica documentation
</label>
<div class="md-nav__source">
<a href="https://github.com/friendica/friendica" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><!--! Font Awesome Free 6.1.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc.--><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg>
</div>
<div class="md-source__repository">
friendica/friendica
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../.." class="md-nav__link">
Home
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2" type="checkbox" id="__nav_2" >
<label class="md-nav__link" for="__nav_2">
User
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="User" data-md-level="1">
<label class="md-nav__title" for="__nav_2">
<span class="md-nav__icon md-icon"></span>
User
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2_1" type="checkbox" id="__nav_2_1" >
<label class="md-nav__link" for="__nav_2_1">
First Steps
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="First Steps" data-md-level="2">
<label class="md-nav__title" for="__nav_2_1">
<span class="md-nav__icon md-icon"></span>
First Steps
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../user/account-basics/" class="md-nav__link">
Account Basics
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2_1_2" type="checkbox" id="__nav_2_1_2" >
<label class="md-nav__link" for="__nav_2_1_2">
Quick Start
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Quick Start" data-md-level="3">
<label class="md-nav__title" for="__nav_2_1_2">
<span class="md-nav__icon md-icon"></span>
Quick Start
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../user/quick-start/guide/" class="md-nav__link">
Start
</a>
</li>
<li class="md-nav__item">
<a href="../../user/quick-start/network/" class="md-nav__link">
Network
</a>
</li>
<li class="md-nav__item">
<a href="../../user/quick-start/groups-and-pages/" class="md-nav__link">
Groups & Pages
</a>
</li>
<li class="md-nav__item">
<a href="../../user/quick-start/making-new-friends/" class="md-nav__link">
Making new friends
</a>
</li>
<li class="md-nav__item">
<a href="../../user/quick-start/finally/" class="md-nav__link">
Finally
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../../user/text-editor/" class="md-nav__link">
Text editor
</a>
</li>
<li class="md-nav__item">
<a href="../../user/bbcode/" class="md-nav__link">
BBCode
</a>
</li>
<li class="md-nav__item">
<a href="../../user/text-comment/" class="md-nav__link">
Comments
</a>
</li>
<li class="md-nav__item">
<a href="../../user/accesskeys/" class="md-nav__link">
Accesskeys
</a>
</li>
<li class="md-nav__item">
<a href="../../user/events/" class="md-nav__link">
Events
</a>
</li>
<li class="md-nav__item">
<a href="../../user/keyboard-shortcuts/" class="md-nav__link">
Shortcuts
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2_2" type="checkbox" id="__nav_2_2" >
<label class="md-nav__link" for="__nav_2_2">
You and other users
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="You and other users" data-md-level="2">
<label class="md-nav__title" for="__nav_2_2">
<span class="md-nav__icon md-icon"></span>
You and other users
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../user/connectors/" class="md-nav__link">
Connectors
</a>
</li>
<li class="md-nav__item">
<a href="../../user/making-friends/" class="md-nav__link">
Making friends
</a>
</li>
<li class="md-nav__item">
<a href="../../user/groups-and-privacy/" class="md-nav__link">
Groups & Privacy
</a>
</li>
<li class="md-nav__item">
<a href="../../user/tags-and-mentions/" class="md-nav__link">
Tags & Mentions
</a>
</li>
<li class="md-nav__item">
<a href="../../user/forums/" class="md-nav__link">
Forums
</a>
</li>
<li class="md-nav__item">
<a href="../../user/chats/" class="md-nav__link">
Chats
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2_3" type="checkbox" id="__nav_2_3" >
<label class="md-nav__link" for="__nav_2_3">
Further information
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Further information" data-md-level="2">
<label class="md-nav__title" for="__nav_2_3">
<span class="md-nav__icon md-icon"></span>
Further information
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../user/move-account/" class="md-nav__link">
Move account
</a>
</li>
<li class="md-nav__item">
<a href="../../user/export-import-contacts/" class="md-nav__link">
Import / Export Contacts
</a>
</li>
<li class="md-nav__item">
<a href="../../user/remove-account/" class="md-nav__link">
Remove account
</a>
</li>
<li class="md-nav__item">
<a href="../../user/two-factor-authentication/" class="md-nav__link">
2FA
</a>
</li>
<li class="md-nav__item">
<a href="../../user/faq/" class="md-nav__link">
FAQ
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_3" type="checkbox" id="__nav_3" >
<label class="md-nav__link" for="__nav_3">
Admin
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Admin" data-md-level="1">
<label class="md-nav__title" for="__nav_3">
<span class="md-nav__icon md-icon"></span>
Admin
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_3_1" type="checkbox" id="__nav_3_1" >
<label class="md-nav__link" for="__nav_3_1">
Installation
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Installation" data-md-level="2">
<label class="md-nav__title" for="__nav_3_1">
<span class="md-nav__icon md-icon"></span>
Installation
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../admin/install/" class="md-nav__link">
Installation
</a>
</li>
<li class="md-nav__item">
<a href="../../admin/update/" class="md-nav__link">
Update
</a>
</li>
<li class="md-nav__item">
<a href="../../admin/migrate/" class="md-nav__link">
Migrate
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_3_2" type="checkbox" id="__nav_3_2" >
<label class="md-nav__link" for="__nav_3_2">
Configuration
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Configuration" data-md-level="2">
<label class="md-nav__title" for="__nav_3_2">
<span class="md-nav__icon md-icon"></span>
Configuration
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../admin/settings/" class="md-nav__link">
Settings
</a>
</li>
<li class="md-nav__item">
<a href="../../admin/config/" class="md-nav__link">
Config Values
</a>
</li>
<li class="md-nav__item">
<a href="../../admin/ssl/" class="md-nav__link">
SSL
</a>
</li>
<li class="md-nav__item">
<a href="../../admin/improve-performance/" class="md-nav__link">
Improve Performance
</a>
</li>
<li class="md-nav__item">
<a href="../../admin/tools/" class="md-nav__link">
Tools
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_3_3" type="checkbox" id="__nav_3_3" >
<label class="md-nav__link" for="__nav_3_3">
Third Party
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Third Party" data-md-level="2">
<label class="md-nav__title" for="__nav_3_3">
<span class="md-nav__icon md-icon"></span>
Third Party
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../admin/installing-connectors/" class="md-nav__link">
Connectors
</a>
</li>
<li class="md-nav__item">
<a href="../../admin/install-ejabberd/" class="md-nav__link">
Install ejabberd
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../../admin/faq/" class="md-nav__link">
FAQ
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_4" type="checkbox" id="__nav_4" checked>
<label class="md-nav__link" for="__nav_4">
Developer
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Developer" data-md-level="1">
<label class="md-nav__title" for="__nav_4">
<span class="md-nav__icon md-icon"></span>
Developer
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../" class="md-nav__link">
Get Started
</a>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_4_2" type="checkbox" id="__nav_4_2" >
<label class="md-nav__link" for="__nav_4_2">
Set Up
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Set Up" data-md-level="2">
<label class="md-nav__title" for="__nav_4_2">
<span class="md-nav__icon md-icon"></span>
Set Up
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../github/" class="md-nav__link">
GitHub
</a>
</li>
<li class="md-nav__item">
<a href="../vagrant/" class="md-nav__link">
Vagrant
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_4_3" type="checkbox" id="__nav_4_3" checked>
<label class="md-nav__link" for="__nav_4_3">
Code structure
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Code structure" data-md-level="2">
<label class="md-nav__title" for="__nav_4_3">
<span class="md-nav__icon md-icon"></span>
Code structure
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../domain-driven-design/" class="md-nav__link">
DDD
</a>
</li>
<li class="md-nav__item">
<a href="../addons/" class="md-nav__link">
Addons
</a>
</li>
<li class="md-nav__item">
<a href="../themes/" class="md-nav__link">
Themes
</a>
</li>
<li class="md-nav__item">
<a href="../smarty3-templates/" class="md-nav__link">
Smarty3
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-nav__toggle md-toggle" data-md-toggle="toc" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
Addon Storage Backend
<span class="md-nav__icon md-icon"></span>
</label>
<a href="./" class="md-nav__link md-nav__link--active">
Addon Storage Backend
</a>
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#the-storage-backend-class" class="md-nav__link">
The Storage Backend Class
</a>
<nav class="md-nav" aria-label="The Storage Backend Class">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#icanwritetostorage" class="md-nav__link">
ICanWriteToStorage
</a>
</li>
<li class="md-nav__item">
<a href="#icanconfigurestorage" class="md-nav__link">
ICanConfigureStorage
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#register-a-storage-backend-class" class="md-nav__link">
Register a storage backend class
</a>
</li>
<li class="md-nav__item">
<a href="#adding-tests" class="md-nav__link">
Adding tests
</a>
</li>
<li class="md-nav__item">
<a href="#exception-handling" class="md-nav__link">
Exception handling
</a>
<nav class="md-nav" aria-label="Exception handling">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#referencestorageexecption" class="md-nav__link">
ReferenceStorageExecption
</a>
</li>
<li class="md-nav__item">
<a href="#storageexception" class="md-nav__link">
StorageException
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#example" class="md-nav__link">
Example
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_4_4" type="checkbox" id="__nav_4_4" >
<label class="md-nav__link" for="__nav_4_4">
How To
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="How To" data-md-level="2">
<label class="md-nav__title" for="__nav_4_4">
<span class="md-nav__icon md-icon"></span>
How To
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../translations/" class="md-nav__link">
Translations
</a>
</li>
<li class="md-nav__item">
<a href="../composer/" class="md-nav__link">
Composer
</a>
</li>
<li class="md-nav__item">
<a href="../how-to-move-classes-to-src/" class="md-nav__link">
src Migration
</a>
</li>
<li class="md-nav__item">
<a href="../tests/" class="md-nav__link">
Tests
</a>
</li>
<li class="md-nav__item">
<a href="../autoloader/" class="md-nav__link">
Autoloader
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_4_5" type="checkbox" id="__nav_4_5" >
<label class="md-nav__link" for="__nav_4_5">
Specification
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Specification" data-md-level="2">
<label class="md-nav__title" for="__nav_4_5">
<span class="md-nav__icon md-icon"></span>
Specification
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_4_5_1" type="checkbox" id="__nav_4_5_1" >
<label class="md-nav__link" for="__nav_4_5_1">
API
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="API" data-md-level="3">
<label class="md-nav__title" for="__nav_4_5_1">
<span class="md-nav__icon md-icon"></span>
API
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../spec/api/" class="md-nav__link">
Usage
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/api/entities/" class="md-nav__link">
Entities
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/api/friendica/" class="md-nav__link">
Friendica
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/api/mastodon/" class="md-nav__link">
Mastodon
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/api/twitter/" class="md-nav__link">
Twitter
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/api/gnu-social/" class="md-nav__link">
GNU Social
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_4_5_2" type="checkbox" id="__nav_4_5_2" >
<label class="md-nav__link" for="__nav_4_5_2">
Database
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Database" data-md-level="3">
<label class="md-nav__title" for="__nav_4_5_2">
<span class="md-nav__icon md-icon"></span>
Database
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../spec/database/" class="md-nav__link">
Database Tables
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_2fa_app_specific_password/" class="md-nav__link">
2fa_app_specific_password
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_2fa_recovery_codes/" class="md-nav__link">
2fa_recovery_codes
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_2fa_trusted_browser/" class="md-nav__link">
2fa_trusted_browser
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_addon/" class="md-nav__link">
addon
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_apcontact/" class="md-nav__link">
apcontact
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_application/" class="md-nav__link">
application
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_application-marker/" class="md-nav__link">
application-marker
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_application-token/" class="md-nav__link">
application-token
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_attach/" class="md-nav__link">
attach
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_cache/" class="md-nav__link">
cache
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_config/" class="md-nav__link">
config
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_contact/" class="md-nav__link">
contact
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_contact-relation/" class="md-nav__link">
contact-relation
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_conv/" class="md-nav__link">
conv
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_conversation/" class="md-nav__link">
conversation
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_delayed-post/" class="md-nav__link">
delayed-post
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_diaspora-interaction/" class="md-nav__link">
diaspora-interaction
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_endpoint/" class="md-nav__link">
endpoint
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_event/" class="md-nav__link">
event
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_fcontact/" class="md-nav__link">
fcontact
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_fsuggest/" class="md-nav__link">
fsuggest
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_group/" class="md-nav__link">
group
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_group_member/" class="md-nav__link">
group_member
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_gserver/" class="md-nav__link">
gserver
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_gserver-tag/" class="md-nav__link">
gserver-tag
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_hook/" class="md-nav__link">
hook
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_inbox-entry/" class="md-nav__link">
inbox-entry
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_inbox-entry-receiver/" class="md-nav__link">
inbox-entry-receiver
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_inbox-status/" class="md-nav__link">
inbox-status
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_intro/" class="md-nav__link">
intro
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_item-uri/" class="md-nav__link">
item-uri
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_locks/" class="md-nav__link">
locks
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_mail/" class="md-nav__link">
mail
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_mailacct/" class="md-nav__link">
mailacct
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_manage/" class="md-nav__link">
manage
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_notification/" class="md-nav__link">
notification
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_notify/" class="md-nav__link">
notify
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_notify-threads/" class="md-nav__link">
notify-threads
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_oembed/" class="md-nav__link">
oembed
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_openwebauth-token/" class="md-nav__link">
openwebauth-token
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_parsed_url/" class="md-nav__link">
parsed_url
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_pconfig/" class="md-nav__link">
pconfig
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_permissionset/" class="md-nav__link">
permissionset
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_photo/" class="md-nav__link">
photo
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_post/" class="md-nav__link">
post
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_post-category/" class="md-nav__link">
post-category
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_post-collection/" class="md-nav__link">
post-collection
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_post-content/" class="md-nav__link">
post-content
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_post-delivery/" class="md-nav__link">
post-delivery
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_post-delivery-data/" class="md-nav__link">
post-delivery-data
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_post-history/" class="md-nav__link">
post-history
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_post-link/" class="md-nav__link">
post-link
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_post-media/" class="md-nav__link">
post-media
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_post-question/" class="md-nav__link">
post-question
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_post-question-option/" class="md-nav__link">
post-question-option
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_post-tag/" class="md-nav__link">
post-tag
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_post-thread/" class="md-nav__link">
post-thread
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_post-thread-user/" class="md-nav__link">
post-thread-user
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_post-user/" class="md-nav__link">
post-user
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_post-user-notification/" class="md-nav__link">
post-user-notification
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_process/" class="md-nav__link">
process
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_profile/" class="md-nav__link">
profile
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_profile_field/" class="md-nav__link">
profile_field
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_push_subscriber/" class="md-nav__link">
push_subscriber
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_register/" class="md-nav__link">
register
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_search/" class="md-nav__link">
search
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_session/" class="md-nav__link">
session
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_storage/" class="md-nav__link">
storage
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_subscription/" class="md-nav__link">
subscription
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_tag/" class="md-nav__link">
tag
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_user/" class="md-nav__link">
user
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_user-contact/" class="md-nav__link">
user-contact
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_userd/" class="md-nav__link">
userd
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_verb/" class="md-nav__link">
verb
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_worker-ipc/" class="md-nav__link">
worker-ipc
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/database/db_workerqueue/" class="md-nav__link">
workerqueue
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_4_5_3" type="checkbox" id="__nav_4_5_3" >
<label class="md-nav__link" for="__nav_4_5_3">
Protocol
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Protocol" data-md-level="3">
<label class="md-nav__title" for="__nav_4_5_3">
<span class="md-nav__icon md-icon"></span>
Protocol
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../spec/protocol/protocol/" class="md-nav__link">
Protocols
</a>
</li>
<li class="md-nav__item">
<a href="../../spec/protocol/message-flow/" class="md-nav__link">
Message Flow
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../../bugs-and-issues/" class="md-nav__link">
Bugs and Issues
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#the-storage-backend-class" class="md-nav__link">
The Storage Backend Class
</a>
<nav class="md-nav" aria-label="The Storage Backend Class">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#icanwritetostorage" class="md-nav__link">
ICanWriteToStorage
</a>
</li>
<li class="md-nav__item">
<a href="#icanconfigurestorage" class="md-nav__link">
ICanConfigureStorage
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#register-a-storage-backend-class" class="md-nav__link">
Register a storage backend class
</a>
</li>
<li class="md-nav__item">
<a href="#adding-tests" class="md-nav__link">
Adding tests
</a>
</li>
<li class="md-nav__item">
<a href="#exception-handling" class="md-nav__link">
Exception handling
</a>
<nav class="md-nav" aria-label="Exception handling">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#referencestorageexecption" class="md-nav__link">
ReferenceStorageExecption
</a>
</li>
<li class="md-nav__item">
<a href="#storageexception" class="md-nav__link">
StorageException
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#example" class="md-nav__link">
Example
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<a href="https://github.com/friendica/friendica/edit/develop/doc/developer/addon-storage-backend.md" title="Edit this page" class="md-content__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25Z"/></svg>
</a>
<nav class="md-tags" >
<span class="md-tag">addon</span>
<span class="md-tag">developer</span>
</nav>
<h1 id="friendica-storage-backend-addon-development">Friendica Storage Backend Addon development<a class="headerlink" href="#friendica-storage-backend-addon-development" title="Permanent link">#</a></h1>
<p>Storage backends can be added via addons.
A storage backend is implemented as a class, and the plugin register the class to make it available to the system.</p>
<h2 id="the-storage-backend-class">The Storage Backend Class<a class="headerlink" href="#the-storage-backend-class" title="Permanent link">#</a></h2>
<p>The class must live in <code>Friendica\Addon\youraddonname</code> namespace, where <code>youraddonname</code> the folder name of your addon.</p>
<p>There are two different interfaces you need to implement.</p>
<h3 id="icanwritetostorage"><code>ICanWriteToStorage</code><a class="headerlink" href="#icanwritetostorage" title="Permanent link">#</a></h3>
<p>The class must implement <code>Friendica\Core\Storage\Capability\ICanWriteToStorage</code> interface. All method in the interface must be implemented:</p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="cp">&lt;?php</span>
<a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a><span class="k">namespace</span> <span class="nx">Friendica\Core\Storage\Capability\ICanWriteToStorage</span><span class="p">;</span>
<a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a>
<a id="__codelineno-0-4" name="__codelineno-0-4" href="#__codelineno-0-4"></a><span class="k">interface</span> <span class="nx">ICanWriteToStorage</span>
<a id="__codelineno-0-5" name="__codelineno-0-5" href="#__codelineno-0-5"></a><span class="p">{</span>
<a id="__codelineno-0-6" name="__codelineno-0-6" href="#__codelineno-0-6"></a> <span class="k">public</span> <span class="k">function</span> <span class="nf">get</span><span class="p">(</span><span class="nx">string</span> <span class="nv">$reference</span><span class="p">);</span>
<a id="__codelineno-0-7" name="__codelineno-0-7" href="#__codelineno-0-7"></a> <span class="k">public</span> <span class="k">function</span> <span class="nf">put</span><span class="p">(</span><span class="nx">string</span> <span class="nv">$data</span><span class="p">,</span> <span class="nx">string</span> <span class="nv">$reference</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="p">);</span>
<a id="__codelineno-0-8" name="__codelineno-0-8" href="#__codelineno-0-8"></a> <span class="k">public</span> <span class="k">function</span> <span class="nf">delete</span><span class="p">(</span><span class="nx">string</span> <span class="nv">$reference</span><span class="p">);</span>
<a id="__codelineno-0-9" name="__codelineno-0-9" href="#__codelineno-0-9"></a> <span class="k">public</span> <span class="k">function</span> <span class="fm">__toString</span><span class="p">();</span>
<a id="__codelineno-0-10" name="__codelineno-0-10" href="#__codelineno-0-10"></a> <span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">getName</span><span class="p">();</span>
<a id="__codelineno-0-11" name="__codelineno-0-11" href="#__codelineno-0-11"></a><span class="p">}</span>
</code></pre></div>
<ul>
<li><code>get(string $reference)</code> returns data pointed by <code>$reference</code></li>
<li><code>put(string $data, string $reference)</code> saves data in <code>$data</code> to position <code>$reference</code>, or a new position if <code>$reference</code> is empty.</li>
<li><code>delete(string $reference)</code> delete data pointed by <code>$reference</code></li>
</ul>
<h3 id="icanconfigurestorage"><code>ICanConfigureStorage</code><a class="headerlink" href="#icanconfigurestorage" title="Permanent link">#</a></h3>
<p>Each storage backend can have options the admin can set in admin page.
To make the options possible, you need to implement the <code>Friendica\Core\Storage\Capability\ICanConfigureStorage</code> interface.</p>
<p>All methods in the interface must be implemented:</p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a><span class="cp">&lt;?php</span>
<a id="__codelineno-1-2" name="__codelineno-1-2" href="#__codelineno-1-2"></a><span class="k">namespace</span> <span class="nx">Friendica\Core\Storage\Capability\ICanConfigureStorage</span><span class="p">;</span>
<a id="__codelineno-1-3" name="__codelineno-1-3" href="#__codelineno-1-3"></a>
<a id="__codelineno-1-4" name="__codelineno-1-4" href="#__codelineno-1-4"></a><span class="k">interface</span> <span class="nx">ICanConfigureStorage</span>
<a id="__codelineno-1-5" name="__codelineno-1-5" href="#__codelineno-1-5"></a><span class="p">{</span>
<a id="__codelineno-1-6" name="__codelineno-1-6" href="#__codelineno-1-6"></a> <span class="k">public</span> <span class="k">function</span> <span class="nf">getOptions</span><span class="p">();</span>
<a id="__codelineno-1-7" name="__codelineno-1-7" href="#__codelineno-1-7"></a> <span class="k">public</span> <span class="k">function</span> <span class="nf">saveOptions</span><span class="p">(</span><span class="k">array</span> <span class="nv">$data</span><span class="p">);</span>
<a id="__codelineno-1-8" name="__codelineno-1-8" href="#__codelineno-1-8"></a><span class="p">}</span>
</code></pre></div>
<ul>
<li><code>getOptions()</code> returns an array with details about each option to build the interface.</li>
<li><code>saveOptions(array $data)</code> get <code>$data</code> from admin page, validate it and save it.</li>
</ul>
<p>The array returned by <code>getOptions()</code> is defined as:</p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a>[
<a id="__codelineno-2-2" name="__codelineno-2-2" href="#__codelineno-2-2"></a> &#39;option1name&#39; =&gt; [ ..info.. ],
<a id="__codelineno-2-3" name="__codelineno-2-3" href="#__codelineno-2-3"></a> &#39;option2name&#39; =&gt; [ ..info.. ],
<a id="__codelineno-2-4" name="__codelineno-2-4" href="#__codelineno-2-4"></a> ...
<a id="__codelineno-2-5" name="__codelineno-2-5" href="#__codelineno-2-5"></a>]
</code></pre></div>
<p>An empty array can be returned if backend doesn't have any options.</p>
<p>The info array for each option is defined as:</p>
<div class="highlight"><pre><span></span><code>[
&#39;type&#39;,
</code></pre></div>
<p>define the field used in form, and the type of data.
one of 'checkbox', 'combobox', 'custom', 'datetime', 'input', 'intcheckbox', 'password', 'radio', 'richtext', 'select', 'select_raw', 'textarea'</p>
<div class="highlight"><pre><span></span><code> &#39;label&#39;,
</code></pre></div>
<p>Translatable label of the field. This label will be shown in admin page</p>
<div class="highlight"><pre><span></span><code> value,
</code></pre></div>
<p>Current value of the option</p>
<div class="highlight"><pre><span></span><code> &#39;help text&#39;,
</code></pre></div>
<p>Translatable description for the field. Will be shown in admin page</p>
<div class="highlight"><pre><span></span><code> extra data
</code></pre></div>
<p>Optional. Depends on which 'type' this option is:</p>
<ul>
<li>'select': array <code>[ value =&gt; label ]</code> of choices</li>
<li>'intcheckbox': value of input element</li>
<li>'select_raw': prebuild html string of <code>&lt;option &gt;</code> tags</li>
</ul>
<p>Each label should be translatable</p>
<div class="highlight"><pre><span></span><code>];
</code></pre></div>
<p>See doxygen documentation of <code>IWritableStorage</code> interface for details about each method.</p>
<h2 id="register-a-storage-backend-class">Register a storage backend class<a class="headerlink" href="#register-a-storage-backend-class" title="Permanent link">#</a></h2>
<p>Each backend must be registered in the system when the plugin is installed, to be aviable.</p>
<p><code>DI::facStorage()-&gt;register(string $class)</code> is used to register the backend class.</p>
<p>When the plugin is uninstalled, registered backends must be unregistered using
<code>DI::facStorage()-&gt;unregister(string $class)</code>.</p>
<p>You have to register a new hook in your addon, listening on <code>storage_instance(App $a, array $data)</code>.
In case <code>$data['name']</code> is your storage class name, you have to instance a new instance of your <code>Friendica\Core\Storage\Capability\ICanReadFromStorage</code> class.
Set the instance of your class as <code>$data['storage']</code> to pass it back to the backend.</p>
<p>This is necessary because it isn't always clear, if you need further construction arguments.</p>
<h2 id="adding-tests">Adding tests<a class="headerlink" href="#adding-tests" title="Permanent link">#</a></h2>
<p><strong>Currently testing is limited to core Friendica only, this shows theoretically how tests should work in the future</strong></p>
<p>Each new Storage class should be added to the test-environment at <a href="https://github.com/friendica/friendica/tree/develop/tests/src/Model/Storage/">Storage Tests</a>.</p>
<p>Add a new test class which's naming convention is <code>StorageClassTest</code>, which extend the <code>StorageTest</code> in the same directory.</p>
<p>Override the two necessary instances:</p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a><span class="x">use Friendica\Core\Storage\Capability\ICanWriteToStorage;</span>
<a id="__codelineno-3-2" name="__codelineno-3-2" href="#__codelineno-3-2"></a>
<a id="__codelineno-3-3" name="__codelineno-3-3" href="#__codelineno-3-3"></a><span class="x">abstract class StorageTest </span>
<a id="__codelineno-3-4" name="__codelineno-3-4" href="#__codelineno-3-4"></a><span class="x">{</span>
<a id="__codelineno-3-5" name="__codelineno-3-5" href="#__codelineno-3-5"></a><span class="x"> // returns an instance of your newly created storage class</span>
<a id="__codelineno-3-6" name="__codelineno-3-6" href="#__codelineno-3-6"></a><span class="x"> abstract protected function getInstance();</span>
<a id="__codelineno-3-7" name="__codelineno-3-7" href="#__codelineno-3-7"></a>
<a id="__codelineno-3-8" name="__codelineno-3-8" href="#__codelineno-3-8"></a><span class="x"> // Assertion for the option array you return for your new StorageClass</span>
<a id="__codelineno-3-9" name="__codelineno-3-9" href="#__codelineno-3-9"></a><span class="x"> abstract protected function assertOption(ICanWriteToStorage $storage);</span>
<a id="__codelineno-3-10" name="__codelineno-3-10" href="#__codelineno-3-10"></a><span class="x">} </span>
</code></pre></div>
<h2 id="exception-handling">Exception handling<a class="headerlink" href="#exception-handling" title="Permanent link">#</a></h2>
<p>There are two intended types of exceptions for storages</p>
<h3 id="referencestorageexecption"><code>ReferenceStorageExecption</code><a class="headerlink" href="#referencestorageexecption" title="Permanent link">#</a></h3>
<p>This storage exception should be used in case the caller tries to use an invalid references.
This could happen in case the caller tries to delete or update an unknown reference.
The implementation of the storage backend must not ignore invalid references.</p>
<p>Avoid throwing the common <code>StorageExecption</code> instead of the <code>ReferenceStorageException</code> at this particular situation!</p>
<h3 id="storageexception"><code>StorageException</code><a class="headerlink" href="#storageexception" title="Permanent link">#</a></h3>
<p>This is the common exception in case unexpected errors happen using the storage backend.
If there's a predecessor to this exception (e.g. you caught an exception and are throwing this execption), you should add the predecessor for transparency reasons.</p>
<p>Example:</p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a><span class="x">use Friendica\Core\Storage\Capability\ICanWriteToStorage;</span>
<a id="__codelineno-4-2" name="__codelineno-4-2" href="#__codelineno-4-2"></a>
<a id="__codelineno-4-3" name="__codelineno-4-3" href="#__codelineno-4-3"></a><span class="x">class ExampleStorage implements ICanWriteToStorage </span>
<a id="__codelineno-4-4" name="__codelineno-4-4" href="#__codelineno-4-4"></a><span class="x">{</span>
<a id="__codelineno-4-5" name="__codelineno-4-5" href="#__codelineno-4-5"></a><span class="x"> public function get(string $reference) : string</span>
<a id="__codelineno-4-6" name="__codelineno-4-6" href="#__codelineno-4-6"></a><span class="x"> {</span>
<a id="__codelineno-4-7" name="__codelineno-4-7" href="#__codelineno-4-7"></a><span class="x"> try {</span>
<a id="__codelineno-4-8" name="__codelineno-4-8" href="#__codelineno-4-8"></a><span class="x"> throw new Exception(&#39;a real bad exception&#39;);</span>
<a id="__codelineno-4-9" name="__codelineno-4-9" href="#__codelineno-4-9"></a><span class="x"> } catch (Exception $exception) {</span>
<a id="__codelineno-4-10" name="__codelineno-4-10" href="#__codelineno-4-10"></a><span class="x"> throw new \Friendica\Core\Storage\Exception\StorageException(sprintf(&#39;The Example Storage throws an exception for reference %s&#39;, $reference), 500, $exception);</span>
<a id="__codelineno-4-11" name="__codelineno-4-11" href="#__codelineno-4-11"></a><span class="x"> }</span>
<a id="__codelineno-4-12" name="__codelineno-4-12" href="#__codelineno-4-12"></a><span class="x"> }</span>
<a id="__codelineno-4-13" name="__codelineno-4-13" href="#__codelineno-4-13"></a><span class="x">} </span>
</code></pre></div>
<h2 id="example">Example<a class="headerlink" href="#example" title="Permanent link">#</a></h2>
<p>Here is a hypothetical addon which register a useless storage backend.
Let's call it <code>samplestorage</code>.</p>
<p>This backend will discard all data we try to save and will return always the same image when we ask for some data.
The image returned can be set by the administrator in admin page.</p>
<p>First, the backend class.
The file will be <code>addon/samplestorage/SampleStorageBackend.php</code>:</p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a><span class="cp">&lt;?php</span>
<a id="__codelineno-5-2" name="__codelineno-5-2" href="#__codelineno-5-2"></a><span class="k">namespace</span> <span class="nx">Friendica\Addon\samplestorage</span><span class="p">;</span>
<a id="__codelineno-5-3" name="__codelineno-5-3" href="#__codelineno-5-3"></a>
<a id="__codelineno-5-4" name="__codelineno-5-4" href="#__codelineno-5-4"></a><span class="k">use</span> <span class="nx">Friendica\Core\Storage\Capability\ICanWriteToStorage</span><span class="p">;</span>
<a id="__codelineno-5-5" name="__codelineno-5-5" href="#__codelineno-5-5"></a>
<a id="__codelineno-5-6" name="__codelineno-5-6" href="#__codelineno-5-6"></a><span class="k">use</span> <span class="nx">Friendica\Core\Config\Capability\IManageConfigValues</span><span class="p">;</span>
<a id="__codelineno-5-7" name="__codelineno-5-7" href="#__codelineno-5-7"></a><span class="k">use</span> <span class="nx">Friendica\Core\L10n</span><span class="p">;</span>
<a id="__codelineno-5-8" name="__codelineno-5-8" href="#__codelineno-5-8"></a>
<a id="__codelineno-5-9" name="__codelineno-5-9" href="#__codelineno-5-9"></a><span class="k">class</span> <span class="nc">SampleStorageBackend</span> <span class="k">implements</span> <span class="nx">ICanWriteToStorage</span>
<a id="__codelineno-5-10" name="__codelineno-5-10" href="#__codelineno-5-10"></a><span class="p">{</span>
<a id="__codelineno-5-11" name="__codelineno-5-11" href="#__codelineno-5-11"></a> <span class="k">const</span> <span class="no">NAME</span> <span class="o">=</span> <span class="s1">&#39;Sample Storage&#39;</span><span class="p">;</span>
<a id="__codelineno-5-12" name="__codelineno-5-12" href="#__codelineno-5-12"></a>
<a id="__codelineno-5-13" name="__codelineno-5-13" href="#__codelineno-5-13"></a> <span class="sd">/** @var string */</span>
<a id="__codelineno-5-14" name="__codelineno-5-14" href="#__codelineno-5-14"></a> <span class="k">private</span> <span class="nv">$filename</span><span class="p">;</span>
<a id="__codelineno-5-15" name="__codelineno-5-15" href="#__codelineno-5-15"></a>
<a id="__codelineno-5-16" name="__codelineno-5-16" href="#__codelineno-5-16"></a> <span class="sd">/**</span>
<a id="__codelineno-5-17" name="__codelineno-5-17" href="#__codelineno-5-17"></a><span class="sd"> * SampleStorageBackend constructor.</span>
<a id="__codelineno-5-18" name="__codelineno-5-18" href="#__codelineno-5-18"></a><span class="sd"> * </span>
<a id="__codelineno-5-19" name="__codelineno-5-19" href="#__codelineno-5-19"></a><span class="sd"> * You can add here every dynamic class as dependency you like and add them to a private field</span>
<a id="__codelineno-5-20" name="__codelineno-5-20" href="#__codelineno-5-20"></a><span class="sd"> * Friendica automatically creates these classes and passes them as argument to the constructor </span>
<a id="__codelineno-5-21" name="__codelineno-5-21" href="#__codelineno-5-21"></a><span class="sd"> */</span>
<a id="__codelineno-5-22" name="__codelineno-5-22" href="#__codelineno-5-22"></a> <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="nx">string</span> <span class="nv">$filename</span><span class="p">)</span>
<a id="__codelineno-5-23" name="__codelineno-5-23" href="#__codelineno-5-23"></a> <span class="p">{</span>
<a id="__codelineno-5-24" name="__codelineno-5-24" href="#__codelineno-5-24"></a> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">filename</span> <span class="o">=</span> <span class="nv">$filename</span><span class="p">;</span>
<a id="__codelineno-5-25" name="__codelineno-5-25" href="#__codelineno-5-25"></a> <span class="p">}</span>
<a id="__codelineno-5-26" name="__codelineno-5-26" href="#__codelineno-5-26"></a>
<a id="__codelineno-5-27" name="__codelineno-5-27" href="#__codelineno-5-27"></a> <span class="k">public</span> <span class="k">function</span> <span class="nf">get</span><span class="p">(</span><span class="nx">string</span> <span class="nv">$reference</span><span class="p">)</span>
<a id="__codelineno-5-28" name="__codelineno-5-28" href="#__codelineno-5-28"></a> <span class="p">{</span>
<a id="__codelineno-5-29" name="__codelineno-5-29" href="#__codelineno-5-29"></a> <span class="c1">// we return always the same image data. Which file we load is defined by</span>
<a id="__codelineno-5-30" name="__codelineno-5-30" href="#__codelineno-5-30"></a> <span class="c1">// a config key</span>
<a id="__codelineno-5-31" name="__codelineno-5-31" href="#__codelineno-5-31"></a> <span class="k">return</span> <span class="nb">file_get_contents</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">filename</span><span class="p">);</span>
<a id="__codelineno-5-32" name="__codelineno-5-32" href="#__codelineno-5-32"></a> <span class="p">}</span>
<a id="__codelineno-5-33" name="__codelineno-5-33" href="#__codelineno-5-33"></a>
<a id="__codelineno-5-34" name="__codelineno-5-34" href="#__codelineno-5-34"></a> <span class="k">public</span> <span class="k">function</span> <span class="nf">put</span><span class="p">(</span><span class="nx">string</span> <span class="nv">$data</span><span class="p">,</span> <span class="nx">string</span> <span class="nv">$reference</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="p">)</span>
<a id="__codelineno-5-35" name="__codelineno-5-35" href="#__codelineno-5-35"></a> <span class="p">{</span>
<a id="__codelineno-5-36" name="__codelineno-5-36" href="#__codelineno-5-36"></a> <span class="k">if</span> <span class="p">(</span><span class="nv">$reference</span> <span class="o">===</span> <span class="s1">&#39;&#39;</span><span class="p">)</span> <span class="p">{</span>
<a id="__codelineno-5-37" name="__codelineno-5-37" href="#__codelineno-5-37"></a> <span class="nv">$reference</span> <span class="o">=</span> <span class="s1">&#39;sample&#39;</span><span class="p">;</span>
<a id="__codelineno-5-38" name="__codelineno-5-38" href="#__codelineno-5-38"></a> <span class="p">}</span>
<a id="__codelineno-5-39" name="__codelineno-5-39" href="#__codelineno-5-39"></a> <span class="c1">// we don&#39;t save $data !</span>
<a id="__codelineno-5-40" name="__codelineno-5-40" href="#__codelineno-5-40"></a> <span class="k">return</span> <span class="nv">$reference</span><span class="p">;</span>
<a id="__codelineno-5-41" name="__codelineno-5-41" href="#__codelineno-5-41"></a> <span class="p">}</span>
<a id="__codelineno-5-42" name="__codelineno-5-42" href="#__codelineno-5-42"></a>
<a id="__codelineno-5-43" name="__codelineno-5-43" href="#__codelineno-5-43"></a> <span class="k">public</span> <span class="k">function</span> <span class="nf">delete</span><span class="p">(</span><span class="nx">string</span> <span class="nv">$reference</span><span class="p">)</span>
<a id="__codelineno-5-44" name="__codelineno-5-44" href="#__codelineno-5-44"></a> <span class="p">{</span>
<a id="__codelineno-5-45" name="__codelineno-5-45" href="#__codelineno-5-45"></a> <span class="c1">// we pretend to delete the data</span>
<a id="__codelineno-5-46" name="__codelineno-5-46" href="#__codelineno-5-46"></a> <span class="k">return</span> <span class="k">true</span><span class="p">;</span>
<a id="__codelineno-5-47" name="__codelineno-5-47" href="#__codelineno-5-47"></a> <span class="p">}</span>
<a id="__codelineno-5-48" name="__codelineno-5-48" href="#__codelineno-5-48"></a>
<a id="__codelineno-5-49" name="__codelineno-5-49" href="#__codelineno-5-49"></a> <span class="k">public</span> <span class="k">function</span> <span class="fm">__toString</span><span class="p">()</span>
<a id="__codelineno-5-50" name="__codelineno-5-50" href="#__codelineno-5-50"></a> <span class="p">{</span>
<a id="__codelineno-5-51" name="__codelineno-5-51" href="#__codelineno-5-51"></a> <span class="k">return</span> <span class="nx">self</span><span class="o">::</span><span class="na">NAME</span><span class="p">;</span>
<a id="__codelineno-5-52" name="__codelineno-5-52" href="#__codelineno-5-52"></a> <span class="p">}</span>
<a id="__codelineno-5-53" name="__codelineno-5-53" href="#__codelineno-5-53"></a>
<a id="__codelineno-5-54" name="__codelineno-5-54" href="#__codelineno-5-54"></a> <span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">getName</span><span class="p">()</span>
<a id="__codelineno-5-55" name="__codelineno-5-55" href="#__codelineno-5-55"></a> <span class="p">{</span>
<a id="__codelineno-5-56" name="__codelineno-5-56" href="#__codelineno-5-56"></a> <span class="k">return</span> <span class="nx">self</span><span class="o">::</span><span class="na">NAME</span><span class="p">;</span>
<a id="__codelineno-5-57" name="__codelineno-5-57" href="#__codelineno-5-57"></a> <span class="p">}</span>
<a id="__codelineno-5-58" name="__codelineno-5-58" href="#__codelineno-5-58"></a><span class="p">}</span>
</code></pre></div>
<div class="highlight"><pre><span></span><code><a id="__codelineno-6-1" name="__codelineno-6-1" href="#__codelineno-6-1"></a><span class="cp">&lt;?php</span>
<a id="__codelineno-6-2" name="__codelineno-6-2" href="#__codelineno-6-2"></a><span class="k">namespace</span> <span class="nx">Friendica\Addon\samplestorage</span><span class="p">;</span>
<a id="__codelineno-6-3" name="__codelineno-6-3" href="#__codelineno-6-3"></a>
<a id="__codelineno-6-4" name="__codelineno-6-4" href="#__codelineno-6-4"></a><span class="k">use</span> <span class="nx">Friendica\Core\Storage\Capability\ICanConfigureStorage</span><span class="p">;</span>
<a id="__codelineno-6-5" name="__codelineno-6-5" href="#__codelineno-6-5"></a>
<a id="__codelineno-6-6" name="__codelineno-6-6" href="#__codelineno-6-6"></a><span class="k">use</span> <span class="nx">Friendica\Core\Config\Capability\IManageConfigValues</span><span class="p">;</span>
<a id="__codelineno-6-7" name="__codelineno-6-7" href="#__codelineno-6-7"></a><span class="k">use</span> <span class="nx">Friendica\Core\L10n</span><span class="p">;</span>
<a id="__codelineno-6-8" name="__codelineno-6-8" href="#__codelineno-6-8"></a>
<a id="__codelineno-6-9" name="__codelineno-6-9" href="#__codelineno-6-9"></a><span class="k">class</span> <span class="nc">SampleStorageBackendConfig</span> <span class="k">implements</span> <span class="nx">ICanConfigureStorage</span>
<a id="__codelineno-6-10" name="__codelineno-6-10" href="#__codelineno-6-10"></a><span class="p">{</span>
<a id="__codelineno-6-11" name="__codelineno-6-11" href="#__codelineno-6-11"></a> <span class="sd">/** @var \Friendica\Core\Config\Capability\IManageConfigValues */</span>
<a id="__codelineno-6-12" name="__codelineno-6-12" href="#__codelineno-6-12"></a> <span class="k">private</span> <span class="nv">$config</span><span class="p">;</span>
<a id="__codelineno-6-13" name="__codelineno-6-13" href="#__codelineno-6-13"></a> <span class="sd">/** @var L10n */</span>
<a id="__codelineno-6-14" name="__codelineno-6-14" href="#__codelineno-6-14"></a> <span class="k">private</span> <span class="nv">$l10n</span><span class="p">;</span>
<a id="__codelineno-6-15" name="__codelineno-6-15" href="#__codelineno-6-15"></a>
<a id="__codelineno-6-16" name="__codelineno-6-16" href="#__codelineno-6-16"></a> <span class="sd">/**</span>
<a id="__codelineno-6-17" name="__codelineno-6-17" href="#__codelineno-6-17"></a><span class="sd"> * SampleStorageBackendConfig constructor.</span>
<a id="__codelineno-6-18" name="__codelineno-6-18" href="#__codelineno-6-18"></a><span class="sd"> * </span>
<a id="__codelineno-6-19" name="__codelineno-6-19" href="#__codelineno-6-19"></a><span class="sd"> * You can add here every dynamic class as dependency you like and add them to a private field</span>
<a id="__codelineno-6-20" name="__codelineno-6-20" href="#__codelineno-6-20"></a><span class="sd"> * Friendica automatically creates these classes and passes them as argument to the constructor </span>
<a id="__codelineno-6-21" name="__codelineno-6-21" href="#__codelineno-6-21"></a><span class="sd"> */</span>
<a id="__codelineno-6-22" name="__codelineno-6-22" href="#__codelineno-6-22"></a> <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="nx">IManageConfigValues</span> <span class="nv">$config</span><span class="p">,</span> <span class="nx">L10n</span> <span class="nv">$l10n</span><span class="p">)</span>
<a id="__codelineno-6-23" name="__codelineno-6-23" href="#__codelineno-6-23"></a> <span class="p">{</span>
<a id="__codelineno-6-24" name="__codelineno-6-24" href="#__codelineno-6-24"></a> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">config</span> <span class="o">=</span> <span class="nv">$config</span><span class="p">;</span>
<a id="__codelineno-6-25" name="__codelineno-6-25" href="#__codelineno-6-25"></a> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">l10n</span> <span class="o">=</span> <span class="nv">$l10n</span><span class="p">;</span>
<a id="__codelineno-6-26" name="__codelineno-6-26" href="#__codelineno-6-26"></a> <span class="p">}</span>
<a id="__codelineno-6-27" name="__codelineno-6-27" href="#__codelineno-6-27"></a>
<a id="__codelineno-6-28" name="__codelineno-6-28" href="#__codelineno-6-28"></a> <span class="k">public</span> <span class="k">function</span> <span class="nf">getFileName</span><span class="p">()</span><span class="o">:</span> <span class="nx">string</span>
<a id="__codelineno-6-29" name="__codelineno-6-29" href="#__codelineno-6-29"></a> <span class="p">{</span>
<a id="__codelineno-6-30" name="__codelineno-6-30" href="#__codelineno-6-30"></a> <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">config</span><span class="o">-&gt;</span><span class="na">get</span><span class="p">(</span><span class="s1">&#39;storage&#39;</span><span class="p">,</span> <span class="s1">&#39;samplestorage&#39;</span><span class="p">,</span> <span class="s1">&#39;sample.jpg&#39;</span><span class="p">);</span>
<a id="__codelineno-6-31" name="__codelineno-6-31" href="#__codelineno-6-31"></a> <span class="p">}</span>
<a id="__codelineno-6-32" name="__codelineno-6-32" href="#__codelineno-6-32"></a>
<a id="__codelineno-6-33" name="__codelineno-6-33" href="#__codelineno-6-33"></a> <span class="k">public</span> <span class="k">function</span> <span class="nf">getOptions</span><span class="p">()</span>
<a id="__codelineno-6-34" name="__codelineno-6-34" href="#__codelineno-6-34"></a> <span class="p">{</span>
<a id="__codelineno-6-35" name="__codelineno-6-35" href="#__codelineno-6-35"></a> <span class="nv">$filename</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">config</span><span class="o">-&gt;</span><span class="na">get</span><span class="p">(</span><span class="s1">&#39;storage&#39;</span><span class="p">,</span> <span class="s1">&#39;samplestorage&#39;</span><span class="p">,</span> <span class="s1">&#39;sample.jpg&#39;</span><span class="p">);</span>
<a id="__codelineno-6-36" name="__codelineno-6-36" href="#__codelineno-6-36"></a> <span class="k">return</span> <span class="p">[</span>
<a id="__codelineno-6-37" name="__codelineno-6-37" href="#__codelineno-6-37"></a> <span class="s1">&#39;filename&#39;</span> <span class="o">=&gt;</span> <span class="p">[</span>
<a id="__codelineno-6-38" name="__codelineno-6-38" href="#__codelineno-6-38"></a> <span class="s1">&#39;input&#39;</span><span class="p">,</span> <span class="c1">// will use a simple text input</span>
<a id="__codelineno-6-39" name="__codelineno-6-39" href="#__codelineno-6-39"></a> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">l10n</span><span class="o">-&gt;</span><span class="na">t</span><span class="p">(</span><span class="s1">&#39;The file to return&#39;</span><span class="p">),</span> <span class="c1">// the label</span>
<a id="__codelineno-6-40" name="__codelineno-6-40" href="#__codelineno-6-40"></a> <span class="nv">$filename</span><span class="p">,</span> <span class="c1">// the current value</span>
<a id="__codelineno-6-41" name="__codelineno-6-41" href="#__codelineno-6-41"></a> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">l10n</span><span class="o">-&gt;</span><span class="na">t</span><span class="p">(</span><span class="s1">&#39;Enter the path to a file&#39;</span><span class="p">),</span> <span class="c1">// the help text</span>
<a id="__codelineno-6-42" name="__codelineno-6-42" href="#__codelineno-6-42"></a> <span class="c1">// no extra data for &#39;input&#39; type..</span>
<a id="__codelineno-6-43" name="__codelineno-6-43" href="#__codelineno-6-43"></a> <span class="p">],</span>
<a id="__codelineno-6-44" name="__codelineno-6-44" href="#__codelineno-6-44"></a> <span class="p">];</span>
<a id="__codelineno-6-45" name="__codelineno-6-45" href="#__codelineno-6-45"></a> <span class="p">}</span>
<a id="__codelineno-6-46" name="__codelineno-6-46" href="#__codelineno-6-46"></a>
<a id="__codelineno-6-47" name="__codelineno-6-47" href="#__codelineno-6-47"></a> <span class="k">public</span> <span class="k">function</span> <span class="nf">saveOptions</span><span class="p">(</span><span class="k">array</span> <span class="nv">$data</span><span class="p">)</span>
<a id="__codelineno-6-48" name="__codelineno-6-48" href="#__codelineno-6-48"></a> <span class="p">{</span>
<a id="__codelineno-6-49" name="__codelineno-6-49" href="#__codelineno-6-49"></a> <span class="c1">// the keys in $data are the same keys we defined in getOptions()</span>
<a id="__codelineno-6-50" name="__codelineno-6-50" href="#__codelineno-6-50"></a> <span class="nv">$newfilename</span> <span class="o">=</span> <span class="nb">trim</span><span class="p">(</span><span class="nv">$data</span><span class="p">[</span><span class="s1">&#39;filename&#39;</span><span class="p">]);</span>
<a id="__codelineno-6-51" name="__codelineno-6-51" href="#__codelineno-6-51"></a>
<a id="__codelineno-6-52" name="__codelineno-6-52" href="#__codelineno-6-52"></a> <span class="c1">// this function should always validate the data.</span>
<a id="__codelineno-6-53" name="__codelineno-6-53" href="#__codelineno-6-53"></a> <span class="c1">// in this example we check if file exists</span>
<a id="__codelineno-6-54" name="__codelineno-6-54" href="#__codelineno-6-54"></a> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nb">file_exists</span><span class="p">(</span><span class="nv">$newfilename</span><span class="p">))</span> <span class="p">{</span>
<a id="__codelineno-6-55" name="__codelineno-6-55" href="#__codelineno-6-55"></a> <span class="c1">// in case of error we return an array with</span>
<a id="__codelineno-6-56" name="__codelineno-6-56" href="#__codelineno-6-56"></a> <span class="c1">// [&#39;optionname&#39; =&gt; &#39;error message&#39;]</span>
<a id="__codelineno-6-57" name="__codelineno-6-57" href="#__codelineno-6-57"></a> <span class="k">return</span> <span class="p">[</span><span class="s1">&#39;filename&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;The file doesn\&#39;t exists&#39;</span><span class="p">];</span>
<a id="__codelineno-6-58" name="__codelineno-6-58" href="#__codelineno-6-58"></a> <span class="p">}</span>
<a id="__codelineno-6-59" name="__codelineno-6-59" href="#__codelineno-6-59"></a>
<a id="__codelineno-6-60" name="__codelineno-6-60" href="#__codelineno-6-60"></a> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">config</span><span class="o">-&gt;</span><span class="na">set</span><span class="p">(</span><span class="s1">&#39;storage&#39;</span><span class="p">,</span> <span class="s1">&#39;samplestorage&#39;</span><span class="p">,</span> <span class="nv">$newfilename</span><span class="p">);</span>
<a id="__codelineno-6-61" name="__codelineno-6-61" href="#__codelineno-6-61"></a>
<a id="__codelineno-6-62" name="__codelineno-6-62" href="#__codelineno-6-62"></a> <span class="c1">// no errors, return empty array</span>
<a id="__codelineno-6-63" name="__codelineno-6-63" href="#__codelineno-6-63"></a> <span class="k">return</span> <span class="p">[];</span>
<a id="__codelineno-6-64" name="__codelineno-6-64" href="#__codelineno-6-64"></a> <span class="p">}</span>
<a id="__codelineno-6-65" name="__codelineno-6-65" href="#__codelineno-6-65"></a>
<a id="__codelineno-6-66" name="__codelineno-6-66" href="#__codelineno-6-66"></a><span class="p">}</span>
</code></pre></div>
<p>Now the plugin main file. Here we register and unregister the backend class.</p>
<p>The file is <code>addon/samplestorage/samplestorage.php</code></p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a><span class="cp">&lt;?php</span>
<a id="__codelineno-7-2" name="__codelineno-7-2" href="#__codelineno-7-2"></a><span class="sd">/**</span>
<a id="__codelineno-7-3" name="__codelineno-7-3" href="#__codelineno-7-3"></a><span class="sd"> * Name: Sample Storage Addon</span>
<a id="__codelineno-7-4" name="__codelineno-7-4" href="#__codelineno-7-4"></a><span class="sd"> * Description: A sample addon which implements an unusefull storage backend</span>
<a id="__codelineno-7-5" name="__codelineno-7-5" href="#__codelineno-7-5"></a><span class="sd"> * Version: 1.0.0</span>
<a id="__codelineno-7-6" name="__codelineno-7-6" href="#__codelineno-7-6"></a><span class="sd"> * Author: Alice &lt;https://alice.social/~alice&gt;</span>
<a id="__codelineno-7-7" name="__codelineno-7-7" href="#__codelineno-7-7"></a><span class="sd"> */</span>
<a id="__codelineno-7-8" name="__codelineno-7-8" href="#__codelineno-7-8"></a>
<a id="__codelineno-7-9" name="__codelineno-7-9" href="#__codelineno-7-9"></a><span class="k">use</span> <span class="nx">Friendica\Addon\samplestorage\SampleStorageBackend</span><span class="p">;</span>
<a id="__codelineno-7-10" name="__codelineno-7-10" href="#__codelineno-7-10"></a><span class="k">use</span> <span class="nx">Friendica\Addon\samplestorage\SampleStorageBackendConfig</span><span class="p">;</span>
<a id="__codelineno-7-11" name="__codelineno-7-11" href="#__codelineno-7-11"></a><span class="k">use</span> <span class="nx">Friendica\DI</span><span class="p">;</span>
<a id="__codelineno-7-12" name="__codelineno-7-12" href="#__codelineno-7-12"></a>
<a id="__codelineno-7-13" name="__codelineno-7-13" href="#__codelineno-7-13"></a><span class="k">function</span> <span class="nf">samplestorage_install</span><span class="p">()</span>
<a id="__codelineno-7-14" name="__codelineno-7-14" href="#__codelineno-7-14"></a><span class="p">{</span>
<a id="__codelineno-7-15" name="__codelineno-7-15" href="#__codelineno-7-15"></a> <span class="nx">Hook</span><span class="o">::</span><span class="na">register</span><span class="p">(</span><span class="s1">&#39;storage_instance&#39;</span> <span class="p">,</span> <span class="no">__FILE__</span><span class="p">,</span> <span class="s1">&#39;samplestorage_storage_instance&#39;</span><span class="p">);</span>
<a id="__codelineno-7-16" name="__codelineno-7-16" href="#__codelineno-7-16"></a> <span class="nx">Hook</span><span class="o">::</span><span class="na">register</span><span class="p">(</span><span class="s1">&#39;storage_config&#39;</span> <span class="p">,</span> <span class="no">__FILE__</span><span class="p">,</span> <span class="s1">&#39;samplestorage_storage_config&#39;</span><span class="p">);</span>
<a id="__codelineno-7-17" name="__codelineno-7-17" href="#__codelineno-7-17"></a> <span class="nx">DI</span><span class="o">::</span><span class="na">storageManager</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">register</span><span class="p">(</span><span class="nx">SampleStorageBackend</span><span class="o">::</span><span class="na">class</span><span class="p">);</span>
<a id="__codelineno-7-18" name="__codelineno-7-18" href="#__codelineno-7-18"></a><span class="p">}</span>
<a id="__codelineno-7-19" name="__codelineno-7-19" href="#__codelineno-7-19"></a>
<a id="__codelineno-7-20" name="__codelineno-7-20" href="#__codelineno-7-20"></a><span class="k">function</span> <span class="nf">samplestorage_storage_uninstall</span><span class="p">()</span>
<a id="__codelineno-7-21" name="__codelineno-7-21" href="#__codelineno-7-21"></a><span class="p">{</span>
<a id="__codelineno-7-22" name="__codelineno-7-22" href="#__codelineno-7-22"></a> <span class="nx">DI</span><span class="o">::</span><span class="na">storageManager</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">unregister</span><span class="p">(</span><span class="nx">SampleStorageBackend</span><span class="o">::</span><span class="na">class</span><span class="p">);</span>
<a id="__codelineno-7-23" name="__codelineno-7-23" href="#__codelineno-7-23"></a><span class="p">}</span>
<a id="__codelineno-7-24" name="__codelineno-7-24" href="#__codelineno-7-24"></a>
<a id="__codelineno-7-25" name="__codelineno-7-25" href="#__codelineno-7-25"></a><span class="k">function</span> <span class="nf">samplestorage_storage_instance</span><span class="p">(</span><span class="nx">App</span> <span class="nv">$a</span><span class="p">,</span> <span class="k">array</span> <span class="o">&amp;</span><span class="nv">$data</span><span class="p">)</span>
<a id="__codelineno-7-26" name="__codelineno-7-26" href="#__codelineno-7-26"></a><span class="p">{</span>
<a id="__codelineno-7-27" name="__codelineno-7-27" href="#__codelineno-7-27"></a> <span class="nv">$config</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">SampleStorageBackendConfig</span><span class="p">(</span><span class="nx">DI</span><span class="o">::</span><span class="na">l10n</span><span class="p">(),</span> <span class="nx">DI</span><span class="o">::</span><span class="na">config</span><span class="p">());</span>
<a id="__codelineno-7-28" name="__codelineno-7-28" href="#__codelineno-7-28"></a> <span class="nv">$data</span><span class="p">[</span><span class="s1">&#39;storage&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">SampleStorageBackendConfig</span><span class="p">(</span><span class="nv">$config</span><span class="o">-&gt;</span><span class="na">getFileName</span><span class="p">());</span>
<a id="__codelineno-7-29" name="__codelineno-7-29" href="#__codelineno-7-29"></a><span class="p">}</span>
<a id="__codelineno-7-30" name="__codelineno-7-30" href="#__codelineno-7-30"></a>
<a id="__codelineno-7-31" name="__codelineno-7-31" href="#__codelineno-7-31"></a><span class="k">function</span> <span class="nf">samplestorage_storage_config</span><span class="p">(</span><span class="nx">App</span> <span class="nv">$a</span><span class="p">,</span> <span class="k">array</span> <span class="o">&amp;</span><span class="nv">$data</span><span class="p">)</span>
<a id="__codelineno-7-32" name="__codelineno-7-32" href="#__codelineno-7-32"></a><span class="p">{</span>
<a id="__codelineno-7-33" name="__codelineno-7-33" href="#__codelineno-7-33"></a> <span class="nv">$data</span><span class="p">[</span><span class="s1">&#39;storage_config&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">SampleStorageBackendConfig</span><span class="p">(</span><span class="nx">DI</span><span class="o">::</span><span class="na">l10n</span><span class="p">(),</span> <span class="nx">DI</span><span class="o">::</span><span class="na">config</span><span class="p">());</span>
<a id="__codelineno-7-34" name="__codelineno-7-34" href="#__codelineno-7-34"></a><span class="p">}</span>
</code></pre></div>
<p>**Theoretically - until tests for Addons are enabled too - create a test class with the name <code>addon/tests/SampleStorageTest.php</code>:</p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-8-1" name="__codelineno-8-1" href="#__codelineno-8-1"></a><span class="x">use Friendica\Core\Storage\Capability\ICanWriteToStorage;</span>
<a id="__codelineno-8-2" name="__codelineno-8-2" href="#__codelineno-8-2"></a><span class="x">use Friendica\Test\src\Core\Storage\StorageTest;</span>
<a id="__codelineno-8-3" name="__codelineno-8-3" href="#__codelineno-8-3"></a>
<a id="__codelineno-8-4" name="__codelineno-8-4" href="#__codelineno-8-4"></a><span class="x">class SampleStorageTest extends StorageTest </span>
<a id="__codelineno-8-5" name="__codelineno-8-5" href="#__codelineno-8-5"></a><span class="x">{</span>
<a id="__codelineno-8-6" name="__codelineno-8-6" href="#__codelineno-8-6"></a><span class="x"> // returns an instance of your newly created storage class</span>
<a id="__codelineno-8-7" name="__codelineno-8-7" href="#__codelineno-8-7"></a><span class="x"> protected function getInstance()</span>
<a id="__codelineno-8-8" name="__codelineno-8-8" href="#__codelineno-8-8"></a><span class="x"> {</span>
<a id="__codelineno-8-9" name="__codelineno-8-9" href="#__codelineno-8-9"></a><span class="x"> // create a new SampleStorageBackend instance with all it&#39;s dependencies</span>
<a id="__codelineno-8-10" name="__codelineno-8-10" href="#__codelineno-8-10"></a><span class="x"> // Have a look at DatabaseStorageTest or FilesystemStorageTest for further insights</span>
<a id="__codelineno-8-11" name="__codelineno-8-11" href="#__codelineno-8-11"></a><span class="x"> return new SampleStorageBackend();</span>
<a id="__codelineno-8-12" name="__codelineno-8-12" href="#__codelineno-8-12"></a><span class="x"> }</span>
<a id="__codelineno-8-13" name="__codelineno-8-13" href="#__codelineno-8-13"></a>
<a id="__codelineno-8-14" name="__codelineno-8-14" href="#__codelineno-8-14"></a><span class="x"> // Assertion for the option array you return for your new StorageClass</span>
<a id="__codelineno-8-15" name="__codelineno-8-15" href="#__codelineno-8-15"></a><span class="x"> protected function assertOption(ICanWriteToStorage $storage)</span>
<a id="__codelineno-8-16" name="__codelineno-8-16" href="#__codelineno-8-16"></a><span class="x"> {</span>
<a id="__codelineno-8-17" name="__codelineno-8-17" href="#__codelineno-8-17"></a><span class="x"> $this-&gt;assertEquals([</span>
<a id="__codelineno-8-18" name="__codelineno-8-18" href="#__codelineno-8-18"></a><span class="x"> &#39;filename&#39; =&gt; [</span>
<a id="__codelineno-8-19" name="__codelineno-8-19" href="#__codelineno-8-19"></a><span class="x"> &#39;input&#39;,</span>
<a id="__codelineno-8-20" name="__codelineno-8-20" href="#__codelineno-8-20"></a><span class="x"> &#39;The file to return&#39;,</span>
<a id="__codelineno-8-21" name="__codelineno-8-21" href="#__codelineno-8-21"></a><span class="x"> &#39;sample.jpg&#39;,</span>
<a id="__codelineno-8-22" name="__codelineno-8-22" href="#__codelineno-8-22"></a><span class="x"> &#39;Enter the path to a file&#39;</span>
<a id="__codelineno-8-23" name="__codelineno-8-23" href="#__codelineno-8-23"></a><span class="x"> ],</span>
<a id="__codelineno-8-24" name="__codelineno-8-24" href="#__codelineno-8-24"></a><span class="x"> ], $storage-&gt;getOptions());</span>
<a id="__codelineno-8-25" name="__codelineno-8-25" href="#__codelineno-8-25"></a><span class="x"> }</span>
<a id="__codelineno-8-26" name="__codelineno-8-26" href="#__codelineno-8-26"></a><span class="x">} </span>
</code></pre></div>
</article>
</div>
</div>
<a href="#" class="md-top md-icon" data-md-component="top" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8v12Z"/></svg>
Back to top
</a>
</main>
<footer class="md-footer">
<nav class="md-footer__inner md-grid" aria-label="Footer" >
<a href="../smarty3-templates/" class="md-footer__link md-footer__link--prev" aria-label="Previous: Smarty3" rel="prev">
<div class="md-footer__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z"/></svg>
</div>
<div class="md-footer__title">
<div class="md-ellipsis">
<span class="md-footer__direction">
Previous
</span>
Smarty3
</div>
</div>
</a>
<a href="../translations/" class="md-footer__link md-footer__link--next" aria-label="Next: Translations" rel="next">
<div class="md-footer__title">
<div class="md-ellipsis">
<span class="md-footer__direction">
Next
</span>
Translations
</div>
</div>
<div class="md-footer__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11H4Z"/></svg>
</div>
</a>
</nav>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
<div class="md-copyright__highlight">
Copyright &copy; 2010-2022, the Friendica project
</div>
Made with
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
Material for MkDocs
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"base": "../..", "features": ["content.code.annotate", "content.tooltips", "navigation.indexes", "navigation.sections", "navigation.tabs", "navigation.top", "navigation.tracking", "search.highlight", "search.share", "search.suggest", "toc.follow"], "search": "../../assets/javascripts/workers/search.b97dbffb.min.js", "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.config.lang": "en", "search.config.pipeline": "trimmer, stopWordFilter", "search.config.separator": "[\\s\\-]+", "search.placeholder": "Search", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version.title": "Select version"}}</script>
<script src="../../assets/javascripts/bundle.0238f547.min.js"></script>
</body>
</html>