1*a1a3b679SAndreas Boehler<?php 2*a1a3b679SAndreas Boehler 3*a1a3b679SAndreas Boehlernamespace Sabre\DAVACL\PrincipalBackend; 4*a1a3b679SAndreas Boehler 5*a1a3b679SAndreas Boehleruse Sabre\DAV; 6*a1a3b679SAndreas Boehleruse Sabre\DAV\MkCol; 7*a1a3b679SAndreas Boehleruse Sabre\HTTP\URLUtil; 8*a1a3b679SAndreas Boehler 9*a1a3b679SAndreas Boehler/** 10*a1a3b679SAndreas Boehler * PDO principal backend 11*a1a3b679SAndreas Boehler * 12*a1a3b679SAndreas Boehler * 13*a1a3b679SAndreas Boehler * This backend assumes all principals are in a single collection. The default collection 14*a1a3b679SAndreas Boehler * is 'principals/', but this can be overriden. 15*a1a3b679SAndreas Boehler * 16*a1a3b679SAndreas Boehler * @copyright Copyright (C) 2007-2015 fruux GmbH (https://fruux.com/). 17*a1a3b679SAndreas Boehler * @author Evert Pot (http://evertpot.com/) 18*a1a3b679SAndreas Boehler * @license http://sabre.io/license/ Modified BSD License 19*a1a3b679SAndreas Boehler */ 20*a1a3b679SAndreas Boehlerclass PDO extends AbstractBackend implements CreatePrincipalSupport { 21*a1a3b679SAndreas Boehler 22*a1a3b679SAndreas Boehler /** 23*a1a3b679SAndreas Boehler * PDO table name for 'principals' 24*a1a3b679SAndreas Boehler * 25*a1a3b679SAndreas Boehler * @var string 26*a1a3b679SAndreas Boehler */ 27*a1a3b679SAndreas Boehler public $tableName = 'principals'; 28*a1a3b679SAndreas Boehler 29*a1a3b679SAndreas Boehler /** 30*a1a3b679SAndreas Boehler * PDO table name for 'group members' 31*a1a3b679SAndreas Boehler * 32*a1a3b679SAndreas Boehler * @var string 33*a1a3b679SAndreas Boehler */ 34*a1a3b679SAndreas Boehler public $groupMembersTableName = 'groupmembers'; 35*a1a3b679SAndreas Boehler 36*a1a3b679SAndreas Boehler /** 37*a1a3b679SAndreas Boehler * pdo 38*a1a3b679SAndreas Boehler * 39*a1a3b679SAndreas Boehler * @var PDO 40*a1a3b679SAndreas Boehler */ 41*a1a3b679SAndreas Boehler protected $pdo; 42*a1a3b679SAndreas Boehler 43*a1a3b679SAndreas Boehler /** 44*a1a3b679SAndreas Boehler * A list of additional fields to support 45*a1a3b679SAndreas Boehler * 46*a1a3b679SAndreas Boehler * @var array 47*a1a3b679SAndreas Boehler */ 48*a1a3b679SAndreas Boehler protected $fieldMap = [ 49*a1a3b679SAndreas Boehler 50*a1a3b679SAndreas Boehler /** 51*a1a3b679SAndreas Boehler * This property can be used to display the users' real name. 52*a1a3b679SAndreas Boehler */ 53*a1a3b679SAndreas Boehler '{DAV:}displayname' => [ 54*a1a3b679SAndreas Boehler 'dbField' => 'displayname', 55*a1a3b679SAndreas Boehler ], 56*a1a3b679SAndreas Boehler 57*a1a3b679SAndreas Boehler /** 58*a1a3b679SAndreas Boehler * This is the users' primary email-address. 59*a1a3b679SAndreas Boehler */ 60*a1a3b679SAndreas Boehler '{http://sabredav.org/ns}email-address' => [ 61*a1a3b679SAndreas Boehler 'dbField' => 'email', 62*a1a3b679SAndreas Boehler ], 63*a1a3b679SAndreas Boehler ]; 64*a1a3b679SAndreas Boehler 65*a1a3b679SAndreas Boehler /** 66*a1a3b679SAndreas Boehler * Sets up the backend. 67*a1a3b679SAndreas Boehler * 68*a1a3b679SAndreas Boehler * @param PDO $pdo 69*a1a3b679SAndreas Boehler */ 70*a1a3b679SAndreas Boehler function __construct(\PDO $pdo) { 71*a1a3b679SAndreas Boehler 72*a1a3b679SAndreas Boehler $this->pdo = $pdo; 73*a1a3b679SAndreas Boehler 74*a1a3b679SAndreas Boehler } 75*a1a3b679SAndreas Boehler 76*a1a3b679SAndreas Boehler /** 77*a1a3b679SAndreas Boehler * Returns a list of principals based on a prefix. 78*a1a3b679SAndreas Boehler * 79*a1a3b679SAndreas Boehler * This prefix will often contain something like 'principals'. You are only 80*a1a3b679SAndreas Boehler * expected to return principals that are in this base path. 81*a1a3b679SAndreas Boehler * 82*a1a3b679SAndreas Boehler * You are expected to return at least a 'uri' for every user, you can 83*a1a3b679SAndreas Boehler * return any additional properties if you wish so. Common properties are: 84*a1a3b679SAndreas Boehler * {DAV:}displayname 85*a1a3b679SAndreas Boehler * {http://sabredav.org/ns}email-address - This is a custom SabreDAV 86*a1a3b679SAndreas Boehler * field that's actualy injected in a number of other properties. If 87*a1a3b679SAndreas Boehler * you have an email address, use this property. 88*a1a3b679SAndreas Boehler * 89*a1a3b679SAndreas Boehler * @param string $prefixPath 90*a1a3b679SAndreas Boehler * @return array 91*a1a3b679SAndreas Boehler */ 92*a1a3b679SAndreas Boehler function getPrincipalsByPrefix($prefixPath) { 93*a1a3b679SAndreas Boehler 94*a1a3b679SAndreas Boehler $fields = [ 95*a1a3b679SAndreas Boehler 'uri', 96*a1a3b679SAndreas Boehler ]; 97*a1a3b679SAndreas Boehler 98*a1a3b679SAndreas Boehler foreach ($this->fieldMap as $key => $value) { 99*a1a3b679SAndreas Boehler $fields[] = $value['dbField']; 100*a1a3b679SAndreas Boehler } 101*a1a3b679SAndreas Boehler $result = $this->pdo->query('SELECT ' . implode(',', $fields) . ' FROM ' . $this->tableName); 102*a1a3b679SAndreas Boehler 103*a1a3b679SAndreas Boehler $principals = []; 104*a1a3b679SAndreas Boehler 105*a1a3b679SAndreas Boehler while ($row = $result->fetch(\PDO::FETCH_ASSOC)) { 106*a1a3b679SAndreas Boehler 107*a1a3b679SAndreas Boehler // Checking if the principal is in the prefix 108*a1a3b679SAndreas Boehler list($rowPrefix) = URLUtil::splitPath($row['uri']); 109*a1a3b679SAndreas Boehler if ($rowPrefix !== $prefixPath) continue; 110*a1a3b679SAndreas Boehler 111*a1a3b679SAndreas Boehler $principal = [ 112*a1a3b679SAndreas Boehler 'uri' => $row['uri'], 113*a1a3b679SAndreas Boehler ]; 114*a1a3b679SAndreas Boehler foreach ($this->fieldMap as $key => $value) { 115*a1a3b679SAndreas Boehler if ($row[$value['dbField']]) { 116*a1a3b679SAndreas Boehler $principal[$key] = $row[$value['dbField']]; 117*a1a3b679SAndreas Boehler } 118*a1a3b679SAndreas Boehler } 119*a1a3b679SAndreas Boehler $principals[] = $principal; 120*a1a3b679SAndreas Boehler 121*a1a3b679SAndreas Boehler } 122*a1a3b679SAndreas Boehler 123*a1a3b679SAndreas Boehler return $principals; 124*a1a3b679SAndreas Boehler 125*a1a3b679SAndreas Boehler } 126*a1a3b679SAndreas Boehler 127*a1a3b679SAndreas Boehler /** 128*a1a3b679SAndreas Boehler * Returns a specific principal, specified by it's path. 129*a1a3b679SAndreas Boehler * The returned structure should be the exact same as from 130*a1a3b679SAndreas Boehler * getPrincipalsByPrefix. 131*a1a3b679SAndreas Boehler * 132*a1a3b679SAndreas Boehler * @param string $path 133*a1a3b679SAndreas Boehler * @return array 134*a1a3b679SAndreas Boehler */ 135*a1a3b679SAndreas Boehler function getPrincipalByPath($path) { 136*a1a3b679SAndreas Boehler 137*a1a3b679SAndreas Boehler $fields = [ 138*a1a3b679SAndreas Boehler 'id', 139*a1a3b679SAndreas Boehler 'uri', 140*a1a3b679SAndreas Boehler ]; 141*a1a3b679SAndreas Boehler 142*a1a3b679SAndreas Boehler foreach ($this->fieldMap as $key => $value) { 143*a1a3b679SAndreas Boehler $fields[] = $value['dbField']; 144*a1a3b679SAndreas Boehler } 145*a1a3b679SAndreas Boehler $stmt = $this->pdo->prepare('SELECT ' . implode(',', $fields) . ' FROM ' . $this->tableName . ' WHERE uri = ?'); 146*a1a3b679SAndreas Boehler $stmt->execute([$path]); 147*a1a3b679SAndreas Boehler 148*a1a3b679SAndreas Boehler $row = $stmt->fetch(\PDO::FETCH_ASSOC); 149*a1a3b679SAndreas Boehler if (!$row) return; 150*a1a3b679SAndreas Boehler 151*a1a3b679SAndreas Boehler $principal = [ 152*a1a3b679SAndreas Boehler 'id' => $row['id'], 153*a1a3b679SAndreas Boehler 'uri' => $row['uri'], 154*a1a3b679SAndreas Boehler ]; 155*a1a3b679SAndreas Boehler foreach ($this->fieldMap as $key => $value) { 156*a1a3b679SAndreas Boehler if ($row[$value['dbField']]) { 157*a1a3b679SAndreas Boehler $principal[$key] = $row[$value['dbField']]; 158*a1a3b679SAndreas Boehler } 159*a1a3b679SAndreas Boehler } 160*a1a3b679SAndreas Boehler return $principal; 161*a1a3b679SAndreas Boehler 162*a1a3b679SAndreas Boehler } 163*a1a3b679SAndreas Boehler 164*a1a3b679SAndreas Boehler /** 165*a1a3b679SAndreas Boehler * Updates one ore more webdav properties on a principal. 166*a1a3b679SAndreas Boehler * 167*a1a3b679SAndreas Boehler * The list of mutations is stored in a Sabre\DAV\PropPatch object. 168*a1a3b679SAndreas Boehler * To do the actual updates, you must tell this object which properties 169*a1a3b679SAndreas Boehler * you're going to process with the handle() method. 170*a1a3b679SAndreas Boehler * 171*a1a3b679SAndreas Boehler * Calling the handle method is like telling the PropPatch object "I 172*a1a3b679SAndreas Boehler * promise I can handle updating this property". 173*a1a3b679SAndreas Boehler * 174*a1a3b679SAndreas Boehler * Read the PropPatch documenation for more info and examples. 175*a1a3b679SAndreas Boehler * 176*a1a3b679SAndreas Boehler * @param string $path 177*a1a3b679SAndreas Boehler * @param DAV\PropPatch $propPatch 178*a1a3b679SAndreas Boehler */ 179*a1a3b679SAndreas Boehler function updatePrincipal($path, DAV\PropPatch $propPatch) { 180*a1a3b679SAndreas Boehler 181*a1a3b679SAndreas Boehler $propPatch->handle(array_keys($this->fieldMap), function($properties) use ($path) { 182*a1a3b679SAndreas Boehler 183*a1a3b679SAndreas Boehler $query = "UPDATE " . $this->tableName . " SET "; 184*a1a3b679SAndreas Boehler $first = true; 185*a1a3b679SAndreas Boehler 186*a1a3b679SAndreas Boehler $values = []; 187*a1a3b679SAndreas Boehler 188*a1a3b679SAndreas Boehler foreach ($properties as $key => $value) { 189*a1a3b679SAndreas Boehler 190*a1a3b679SAndreas Boehler $dbField = $this->fieldMap[$key]['dbField']; 191*a1a3b679SAndreas Boehler 192*a1a3b679SAndreas Boehler if (!$first) { 193*a1a3b679SAndreas Boehler $query .= ', '; 194*a1a3b679SAndreas Boehler } 195*a1a3b679SAndreas Boehler $first = false; 196*a1a3b679SAndreas Boehler $query .= $dbField . ' = :' . $dbField; 197*a1a3b679SAndreas Boehler $values[$dbField] = $value; 198*a1a3b679SAndreas Boehler 199*a1a3b679SAndreas Boehler } 200*a1a3b679SAndreas Boehler 201*a1a3b679SAndreas Boehler $query .= " WHERE uri = :uri"; 202*a1a3b679SAndreas Boehler $values['uri'] = $path; 203*a1a3b679SAndreas Boehler 204*a1a3b679SAndreas Boehler $stmt = $this->pdo->prepare($query); 205*a1a3b679SAndreas Boehler $stmt->execute($values); 206*a1a3b679SAndreas Boehler 207*a1a3b679SAndreas Boehler return true; 208*a1a3b679SAndreas Boehler 209*a1a3b679SAndreas Boehler }); 210*a1a3b679SAndreas Boehler 211*a1a3b679SAndreas Boehler } 212*a1a3b679SAndreas Boehler 213*a1a3b679SAndreas Boehler /** 214*a1a3b679SAndreas Boehler * This method is used to search for principals matching a set of 215*a1a3b679SAndreas Boehler * properties. 216*a1a3b679SAndreas Boehler * 217*a1a3b679SAndreas Boehler * This search is specifically used by RFC3744's principal-property-search 218*a1a3b679SAndreas Boehler * REPORT. 219*a1a3b679SAndreas Boehler * 220*a1a3b679SAndreas Boehler * The actual search should be a unicode-non-case-sensitive search. The 221*a1a3b679SAndreas Boehler * keys in searchProperties are the WebDAV property names, while the values 222*a1a3b679SAndreas Boehler * are the property values to search on. 223*a1a3b679SAndreas Boehler * 224*a1a3b679SAndreas Boehler * By default, if multiple properties are submitted to this method, the 225*a1a3b679SAndreas Boehler * various properties should be combined with 'AND'. If $test is set to 226*a1a3b679SAndreas Boehler * 'anyof', it should be combined using 'OR'. 227*a1a3b679SAndreas Boehler * 228*a1a3b679SAndreas Boehler * This method should simply return an array with full principal uri's. 229*a1a3b679SAndreas Boehler * 230*a1a3b679SAndreas Boehler * If somebody attempted to search on a property the backend does not 231*a1a3b679SAndreas Boehler * support, you should simply return 0 results. 232*a1a3b679SAndreas Boehler * 233*a1a3b679SAndreas Boehler * You can also just return 0 results if you choose to not support 234*a1a3b679SAndreas Boehler * searching at all, but keep in mind that this may stop certain features 235*a1a3b679SAndreas Boehler * from working. 236*a1a3b679SAndreas Boehler * 237*a1a3b679SAndreas Boehler * @param string $prefixPath 238*a1a3b679SAndreas Boehler * @param array $searchProperties 239*a1a3b679SAndreas Boehler * @param string $test 240*a1a3b679SAndreas Boehler * @return array 241*a1a3b679SAndreas Boehler */ 242*a1a3b679SAndreas Boehler function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') { 243*a1a3b679SAndreas Boehler 244*a1a3b679SAndreas Boehler $query = 'SELECT uri FROM ' . $this->tableName . ' WHERE 1=1 '; 245*a1a3b679SAndreas Boehler $values = []; 246*a1a3b679SAndreas Boehler foreach ($searchProperties as $property => $value) { 247*a1a3b679SAndreas Boehler 248*a1a3b679SAndreas Boehler switch ($property) { 249*a1a3b679SAndreas Boehler 250*a1a3b679SAndreas Boehler case '{DAV:}displayname' : 251*a1a3b679SAndreas Boehler $query .= ' AND displayname LIKE ?'; 252*a1a3b679SAndreas Boehler $values[] = '%' . $value . '%'; 253*a1a3b679SAndreas Boehler break; 254*a1a3b679SAndreas Boehler case '{http://sabredav.org/ns}email-address' : 255*a1a3b679SAndreas Boehler $query .= ' AND email LIKE ?'; 256*a1a3b679SAndreas Boehler $values[] = '%' . $value . '%'; 257*a1a3b679SAndreas Boehler break; 258*a1a3b679SAndreas Boehler default : 259*a1a3b679SAndreas Boehler // Unsupported property 260*a1a3b679SAndreas Boehler return []; 261*a1a3b679SAndreas Boehler 262*a1a3b679SAndreas Boehler } 263*a1a3b679SAndreas Boehler 264*a1a3b679SAndreas Boehler } 265*a1a3b679SAndreas Boehler $stmt = $this->pdo->prepare($query); 266*a1a3b679SAndreas Boehler $stmt->execute($values); 267*a1a3b679SAndreas Boehler 268*a1a3b679SAndreas Boehler $principals = []; 269*a1a3b679SAndreas Boehler while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { 270*a1a3b679SAndreas Boehler 271*a1a3b679SAndreas Boehler // Checking if the principal is in the prefix 272*a1a3b679SAndreas Boehler list($rowPrefix) = URLUtil::splitPath($row['uri']); 273*a1a3b679SAndreas Boehler if ($rowPrefix !== $prefixPath) continue; 274*a1a3b679SAndreas Boehler 275*a1a3b679SAndreas Boehler $principals[] = $row['uri']; 276*a1a3b679SAndreas Boehler 277*a1a3b679SAndreas Boehler } 278*a1a3b679SAndreas Boehler 279*a1a3b679SAndreas Boehler return $principals; 280*a1a3b679SAndreas Boehler 281*a1a3b679SAndreas Boehler } 282*a1a3b679SAndreas Boehler 283*a1a3b679SAndreas Boehler /** 284*a1a3b679SAndreas Boehler * Returns the list of members for a group-principal 285*a1a3b679SAndreas Boehler * 286*a1a3b679SAndreas Boehler * @param string $principal 287*a1a3b679SAndreas Boehler * @return array 288*a1a3b679SAndreas Boehler */ 289*a1a3b679SAndreas Boehler function getGroupMemberSet($principal) { 290*a1a3b679SAndreas Boehler 291*a1a3b679SAndreas Boehler $principal = $this->getPrincipalByPath($principal); 292*a1a3b679SAndreas Boehler if (!$principal) throw new DAV\Exception('Principal not found'); 293*a1a3b679SAndreas Boehler 294*a1a3b679SAndreas Boehler $stmt = $this->pdo->prepare('SELECT principals.uri as uri FROM ' . $this->groupMembersTableName . ' AS groupmembers LEFT JOIN ' . $this->tableName . ' AS principals ON groupmembers.member_id = principals.id WHERE groupmembers.principal_id = ?'); 295*a1a3b679SAndreas Boehler $stmt->execute([$principal['id']]); 296*a1a3b679SAndreas Boehler 297*a1a3b679SAndreas Boehler $result = []; 298*a1a3b679SAndreas Boehler while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { 299*a1a3b679SAndreas Boehler $result[] = $row['uri']; 300*a1a3b679SAndreas Boehler } 301*a1a3b679SAndreas Boehler return $result; 302*a1a3b679SAndreas Boehler 303*a1a3b679SAndreas Boehler } 304*a1a3b679SAndreas Boehler 305*a1a3b679SAndreas Boehler /** 306*a1a3b679SAndreas Boehler * Returns the list of groups a principal is a member of 307*a1a3b679SAndreas Boehler * 308*a1a3b679SAndreas Boehler * @param string $principal 309*a1a3b679SAndreas Boehler * @return array 310*a1a3b679SAndreas Boehler */ 311*a1a3b679SAndreas Boehler function getGroupMembership($principal) { 312*a1a3b679SAndreas Boehler 313*a1a3b679SAndreas Boehler $principal = $this->getPrincipalByPath($principal); 314*a1a3b679SAndreas Boehler if (!$principal) throw new DAV\Exception('Principal not found'); 315*a1a3b679SAndreas Boehler 316*a1a3b679SAndreas Boehler $stmt = $this->pdo->prepare('SELECT principals.uri as uri FROM ' . $this->groupMembersTableName . ' AS groupmembers LEFT JOIN ' . $this->tableName . ' AS principals ON groupmembers.principal_id = principals.id WHERE groupmembers.member_id = ?'); 317*a1a3b679SAndreas Boehler $stmt->execute([$principal['id']]); 318*a1a3b679SAndreas Boehler 319*a1a3b679SAndreas Boehler $result = []; 320*a1a3b679SAndreas Boehler while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { 321*a1a3b679SAndreas Boehler $result[] = $row['uri']; 322*a1a3b679SAndreas Boehler } 323*a1a3b679SAndreas Boehler return $result; 324*a1a3b679SAndreas Boehler 325*a1a3b679SAndreas Boehler } 326*a1a3b679SAndreas Boehler 327*a1a3b679SAndreas Boehler /** 328*a1a3b679SAndreas Boehler * Updates the list of group members for a group principal. 329*a1a3b679SAndreas Boehler * 330*a1a3b679SAndreas Boehler * The principals should be passed as a list of uri's. 331*a1a3b679SAndreas Boehler * 332*a1a3b679SAndreas Boehler * @param string $principal 333*a1a3b679SAndreas Boehler * @param array $members 334*a1a3b679SAndreas Boehler * @return void 335*a1a3b679SAndreas Boehler */ 336*a1a3b679SAndreas Boehler function setGroupMemberSet($principal, array $members) { 337*a1a3b679SAndreas Boehler 338*a1a3b679SAndreas Boehler // Grabbing the list of principal id's. 339*a1a3b679SAndreas Boehler $stmt = $this->pdo->prepare('SELECT id, uri FROM ' . $this->tableName . ' WHERE uri IN (? ' . str_repeat(', ? ', count($members)) . ');'); 340*a1a3b679SAndreas Boehler $stmt->execute(array_merge([$principal], $members)); 341*a1a3b679SAndreas Boehler 342*a1a3b679SAndreas Boehler $memberIds = []; 343*a1a3b679SAndreas Boehler $principalId = null; 344*a1a3b679SAndreas Boehler 345*a1a3b679SAndreas Boehler while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { 346*a1a3b679SAndreas Boehler if ($row['uri'] == $principal) { 347*a1a3b679SAndreas Boehler $principalId = $row['id']; 348*a1a3b679SAndreas Boehler } else { 349*a1a3b679SAndreas Boehler $memberIds[] = $row['id']; 350*a1a3b679SAndreas Boehler } 351*a1a3b679SAndreas Boehler } 352*a1a3b679SAndreas Boehler if (!$principalId) throw new DAV\Exception('Principal not found'); 353*a1a3b679SAndreas Boehler 354*a1a3b679SAndreas Boehler // Wiping out old members 355*a1a3b679SAndreas Boehler $stmt = $this->pdo->prepare('DELETE FROM ' . $this->groupMembersTableName . ' WHERE principal_id = ?;'); 356*a1a3b679SAndreas Boehler $stmt->execute([$principalId]); 357*a1a3b679SAndreas Boehler 358*a1a3b679SAndreas Boehler foreach ($memberIds as $memberId) { 359*a1a3b679SAndreas Boehler 360*a1a3b679SAndreas Boehler $stmt = $this->pdo->prepare('INSERT INTO ' . $this->groupMembersTableName . ' (principal_id, member_id) VALUES (?, ?);'); 361*a1a3b679SAndreas Boehler $stmt->execute([$principalId, $memberId]); 362*a1a3b679SAndreas Boehler 363*a1a3b679SAndreas Boehler } 364*a1a3b679SAndreas Boehler 365*a1a3b679SAndreas Boehler } 366*a1a3b679SAndreas Boehler 367*a1a3b679SAndreas Boehler /** 368*a1a3b679SAndreas Boehler * Creates a new principal. 369*a1a3b679SAndreas Boehler * 370*a1a3b679SAndreas Boehler * This method receives a full path for the new principal. The mkCol object 371*a1a3b679SAndreas Boehler * contains any additional webdav properties specified during the creation 372*a1a3b679SAndreas Boehler * of the principal. 373*a1a3b679SAndreas Boehler * 374*a1a3b679SAndreas Boehler * @param string $path 375*a1a3b679SAndreas Boehler * @param MkCol $mkCol 376*a1a3b679SAndreas Boehler * @return void 377*a1a3b679SAndreas Boehler */ 378*a1a3b679SAndreas Boehler function createPrincipal($path, MkCol $mkCol) { 379*a1a3b679SAndreas Boehler 380*a1a3b679SAndreas Boehler $stmt = $this->pdo->prepare('INSERT INTO ' . $this->tableName . ' (uri) VALUES (?)'); 381*a1a3b679SAndreas Boehler $stmt->execute([$path]); 382*a1a3b679SAndreas Boehler $this->updatePrincipal($path, $mkCol); 383*a1a3b679SAndreas Boehler 384*a1a3b679SAndreas Boehler } 385*a1a3b679SAndreas Boehler 386*a1a3b679SAndreas Boehler} 387