building a CMS for
ambitious editors
history
born under
the TYPO3 umbrella
goals
foundation
FLOW
full stack PHP framework
yet an other framework
convention over
configuration
security framework
privilegeTargets:
'TYPO3FlowSecurityAuthorizationPrivilegeMethodMethodPrivilege':
'Acme.MyPackage:RestrictedController.customerAction':
matcher: 'method(AcmeMyPackageControllerRestrictedController->
customerAction())'
'Acme.MyPackage:RestrictedController.adminAction':
matcher: 'method(AcmeMyPackageControllerRestrictedController->
(admin|drop)Action())’
'Acme.MyPackage:editOwnPost':
matcher: ‘method(AcmeMyPackageControllerPostController->
editAction(post.owner == current.userService.currentUser))'
roles:
'Acme.MyPackage:Customer':
privileges:
-
privilegeTarget: 'Acme.MyPackage:RestrictedController.customerAction'
permission: GRANT
-
privilegeTarget: 'Acme.MyPackage:RestrictedController.adminAction'
permission: GRANT
-
privilegeTarget: 'Acme.MyPackage:RestrictedController.editOwnPost'
permission: GRANT
'Acme.MyPackage:Customer':
privileges:
-
privilegeTarget: 'Acme.MyPackage:RestrictedController.customerAction'
permission: GRANT
'Acme.MyPackage:PrivilegedCustomer':
parentRoles: ['Acme.MyPackage:Customer']
privileges:
-
privilegeTarget: 'Acme.MyPackage:RestrictedController.editOwnPost'
permission: GRANT
security CLI helpers
$ ./flow security:showunprotectedactions
TYPO3NeosControllerBackendContentController
initializeUploadAssetAction
initializeCreateImageVariantAction
TYPO3NeosControllerLoginController
initializeIndexAction
TYPO3NeosControllerServiceWorkspacesController
initializeUpdateAction
TtreeCloudButlerControllerJobController
initializeRegisterAction
AOP
help with single
responsibility principle
danger zone
We compile your code
Powerful Reflection API
@FlowCompileStatic
/**
* Returns a map of action method names and their parameters.
*
* @param TYPO3FlowObjectObjectManagerInterface $objectManager
* @return array Array of method parameters by action name
* @FlowCompileStatic
*/
static public function getActionMethodParameters($objectManager) {
$reflectionService = $objectManager->get(
'TYPO3FlowReflectionReflectionService');
$className = get_called_class();
$methodParameters = $reflectionService->getMethodParameters($className,
get_class_methods($className));
foreach ($methodParameters as $parameterName => $parameterInfo) {
...
}
return $methodParameters;
}
NEOS is just a package
NEOS Content Repository
where content lives
yaml configuration
'My.Package:SpecialHeadline':
superTypes:
'TYPO3.Neos:Content': true
ui:
label: 'Special Headline'
group: 'general'
properties:
headline:
type: 'string'
defaultValue: 'My Headline Default'
ui:
inlineEditable: true
validation:
'TYPO3.Neos/Validation/StringLengthValidator':
minimum: 1
maximum: 255
inspired by PHPCR
editing content
editor experience
workspace
content dimensions
contents lives
in multiple contexts
WYSIFTW
developer
don’t hide features
create values
flexible content structure
modern rendering stack
fusion
prototype(Vendor:Staff) < prototype(TYPO3.Neos:Content) {
templatePath = ‘resource://Vendor.Site/Private/Templates/ElementName.html'
headline = ${q(node).property('headline')}
subheadline = ${q(node).property('subheadline')}
text = ${q(node).property('text')}
image = ${q(node).property('image')}
}
prototype(Vendor:Staff) < prototype(TYPO3.Neos:Content) {
templatePath = ‘resource://Vendor.Site/Private/Templates/ElementName.html'
headline = ${q(node).property('headline')}
subheadline = ${q(node).property('subheadline')}
text = ${q(node).property('text')}
image = ${q(node).property(‘image’)}
staffIdentifier = ${q(node).property(‘staffIdentifier’)}
staffIdentifier.@process.callErp = ${ErpApi.getStaffDetails(value)}
}
prototype(Vendor:YourTwoColumns) {
prototype(Vendor:Staff) {
templatePath = ‘resource://Vendor.Site/Private/Templates/Compact.html'
}
}
prototype(Vendor:StaffDirectory.Document) {
prototype(Vendor:Staff) {
templatePath = ‘resource://Vendor.Site/Private/Templates/Square.html'
staffPageLink = ${q(node).property(‘staffIdentifier’)}
staffPageLink.@process.callErp = ${ErpApi.getStaffUri(value)}
}
}
prototype(Vendor:StaffListing) < prototype(Flowpack.Listable:Listable) {
@context.limit = 10
collection = ${q(site).find('[instanceof Vendor:Staff]’).get()}
itemRenderer = ‘Vendor:StaffListingItem'
}
prototype(Vendor:StaffListingItem) < prototype(Vendor:Staff) {
templatePath = ‘resource://Vendor.Site/Private/Templates/ListingItem.html'
}
cache on steroid
prototype(Vendor:StaffListingItem) {
@cache {
mode = 'cached'
maximumLifetime = '86400'
entryIdentifier {
node = ${node}
}
entryTags {
1 = ${'Node_' + documentNode.identifier}
}
}
}
much much more
open to organize a workshop to build
something on top of NEOS
from the lab
CQRS
for the content repository
touch points
neos.io
hello@ttree.ch - @ttreeagency - github.com/ttreeagency
tt ttree
digital beans

Liiptalk Neos CMS