Liaison Development Status
Work in Progress (lia\Simple)
- error page
- DNOE displays /generic-error-page/
- DONE need to cache the result to disk so it can be displayed on error
- analytics
- DONE analytics are enabled
- DONE todo need a way to create the analytics table
- DONE need to add the analytics phad view
- other
- add cli command to initialize the user database tables
- add cli command to generate sitemaps
- add cli command to regenerate all phad items
- add cli command to clear the cache
themes
- $lia->setTheme('name/of-theme');
- $theme = new \Lia\Theme('name/of-theme');
- $response->sendHeaders();
- $theme->setContent($response->content);
- $theme->display();
- themes can be found in the view folder or theme folder
- themes are available globally (if any app makes
theme
dir, those themes are shared) - theme is a subclass of view and has extra features (maybe)
How do I test this?
Create a Lia\Simple instance
initialize it?
create an app with several themes in it
set the theme
add a route for /
getResponse() for /
check output of $response->content
WARNING
i did some work to cache routes, but decided not to finish the work but now i want to get rid of that code but maybe i want to keep it around and atm i don't care to work on this more so don't commit this in its current state Okay?
TODO
- base url just doesn't work any more
- re-enable config.json
- testing with my user lib, v0.6 seems to be slower than v0.5 and i DONT UNDERSTAND
- Improve varDelim. varDelim is an awful mechanism bc it applies globally to all routes
- Compile list of views to reduce disk scanning
Changes required with this new version
- addons & packages are no longer liaison objects
- chained
$package_or_addon->lia->method()
must be used to call a global method, instead of calling it directly on the package or the addon. - addons MUST receive a \Lia\Package or null (instead of a liaison object)
- addons MUST set
public string $fqn = 'ns:package_name.addon_name'
- remove all
$lia->props[]
uses -
$lia->addons['key']
always points to an addon, never to a package. use$lia->packages['namespace:key']
for a package. -
$lia->set('server.server.useTheme', false);
now must be$lia->set('lia:server.server.useTheme')
or$lia->set('server.useTheme')
- it's either fully qualified name or JUST the addon name (no namespace) -
new \Lia\Package($lia, 'ns:package_name', $dir)
, thens:package_name
.$dir
is still optional, but$lia
& the package name are now required.- though, name is optional for the server package... hmmm....
-
config.json
inside a package dir is not currently loaded at all (this will be re-enabled as i figure out what i need from it) -
$package->addon_name
no longer works at all, must use$package->addons['addon_name']
or re-write the__get
that will return the addon -
$addon->init_lia()
must be called to setup global methods & such. This is handled automatically by the Server package, though. -
$addon->lia
now points to a\Lia
object and NOT it's parent/package object
Issues to fix with v0.6
- I can't change the cache dir. calling
$lia->set('cache.dir')
can only be used after the Cache & Resource addons are initialized. ButonPackageReady()
calls scan() on the resource addon, seting up routes.onPackageReady()
is called before i have access to the instantiated addon. This is a pervasive issue. Generally, i have no way to pass configurations to addons at time of their construction. I could use fqns, maybe... likelia->set('lia:server.cache.dir)
then whenlia:server.cache
is added to$lia->addons()
i dump all values from that fqn onto the cache addon. I was previously (in v0.5) doing this with references to$lia->props
, which sucked. I could use$lia->addAddon()
method (would require a change to addon class), then do this propagation duringaddAddon()
.
Notes
- default name for server package is
lia:server
, and i really don't like that. - need to review & clean up some code & docs
- i WILL need global properties on the liaison object itself.
- i'm having issues with
set()
calls that didn't specify package, or didn't specify namespace, or were called BEFORE the addon is instantiated.
Apr 26, 2022
New Style:
- Addons go in packages AND liaison
- Packages go in liaison
Package no longer extends from Addon. I removed some things from Lia, Package, and Addon & made it all much simpler. I made addons require fqn, though name is still optional. I made $lia->get()
& set()
only work on addons, working both with fqn addon key & non-fqn addon keys
I also just ... removed some things that seemed complicated? idr what exactly.
- removed
$name
from addon constructor, since it doesn't really make sense to make addon names configurable. (all addon usefulness is INSIDE the addon)
Updated Server package to remove complexities, ... commented out code that sets config.json
to $package->props[]
& i'll need to figure out what to do with those configs.
I updated types of $fqn
and $name
on server package & addons to string
. All but 5 tests are failing now. I suspect the requirement of having an actual package instance will be a big cause of this.
In theory, many addons should be useable on their own. Like I don't think cache or view actually requires any features of package in order to function. But maybe they do? Idunno. I might remove the requirement that package be non-nullable.
I just made package (& lia) optional in addon. but the cache fails because it sets lia->methods
... so idunno what to do about that.
It might be nice to have separate initialization methods to setup liaison (that is separate from the constructor). Same goes for package? idk. That's a future problem.
Apr 21, 2022
There are some features I just want to remove from Liaison or otherwise significantly change.
It's nice that $lia->get()
& $lia->set()
can reach into packages & into addons. It's also a waste of resources, generally speaking.
I used to have this really ... anything goes mindset about liaison, which just makes it hard to ... have the things I want go.
So we have:
- Liaison/Lia: Central piece which gives you access to methods, properties, addons, and packages
- Package: Initializes & holds a group of addons
- Addon: actually does something
In Liaison:
- addons
- packages
- props???
- ... idk ...
Old Features
- set (& get)
- KEEP? set('package.addon.property', value)
- DELETE set('array_key.property', value)
- KEEP set('addon.property', value)
- DELETE
$lia->props['key']['subkey'] ...
- DELETE addon is a lia instance
- DELETE package is a lia instance
- calling methods
- DELETE
$addon->global_method()
- KEEP
$lia->global_method()
- DELETE
$this->methods[key] = ...
(on an addon) ... change to$this->lia->methods[key]
- DELETE
I'm having inconsistency issues ...
- lia:package.addon.prop = value
- package.addon.prop = value
- addon.prop = value
- package.prop = value
I'm gonna just have to drop some of the features.
I think the biggest issue I'm going to have with this refactor is figuring out which tests are better for deleting. I think many of my tests will just need to be deleted because they're testing internal functionality that was never truly needed.
I COULD create some wrappers & stuff to make the current api continue working exactly as it is.
I'm going ot have issue copying config array to its addons, possibly though.
TODO (v0.6)
- review this 600+ line file & relegate most stuff into a history.md file or just delete it. Really, most of it need not be read, such as the day-to-day updates that are written lengthily.
- benchmark diff between an object calling another object implementing interface vs an object calling a method in an array through
__call()
... if the interfaced approach is significantly faster, then perhaps Liaison is just a complete bust & i should abandon it (though i'm not likely going to)
This new version
v0.5 is really slow compared to v0.3. On one of my sites, testing 11 pages went from about 350ms to about 550ms on my localhost. That's ... terrible. 550 / 11 = 50ms per request from 350 / 11 = ~34.8ms. 50ms server response time is awful. I'd like it to be less than 20ms, esepecially with all the overhead of https + script & css files + being on shared hosting.
There is also some quality-of-life stuff i'd like to do
Performance
I believe the main reasons for this slowness are:
- by-reference properties
- multi-dim properties array
- package & addon are subclasses of lia (and the implementation surrounding this is unnecessarily complex)
My solutions are to:
- rewrite
get()
to retrieve an addon & then return a property of the addon- maybe return this by-reference??
- rewrite
set()
to retrieve an addon & then set the property to the addon - rewrite
append()
basically same way asset()
- I don't know what to do about
default()
- i COULD still have a
props
array that just storesnamespace:dot.property=>value
instead of using nested arrays with by-reference
- i COULD still have a
- rewrite
dump()
to retrieve all public properties from all addons manually & ... well dump doesn't need to be performant at all bc it is very limited debugging purposes - remove
copy()
method
Polish / Ease of use
-
setup()
method: I might add a separatesetup()
method for addons & packages that is called after the constructor so that configuration can be done after instantiation, before initializing everything - ... idk ... there's other things.
Other Notes
- extending from
Addon
should never be required to integrate a method or hook with liaison - The
Addon
class should have some nice convenience for setting up addons:- shared methods
- add self to liaison->addons[]
- shared properties
- hooks
- built-in hooks for like
onCreated
,onPackageReady
,onServerReady
- maybe hooks should be a part of liaison's core
What even is the purpose of liaison?
- Create packages for websites that are easily shared & integrated into other sites
- Extremely easy on-boarding
- Integrate with non-liaison websystems
Benchmarking
phptest -class Benchmark
with 100,000 loops yields:
- InterfaceObjectUsingCall 34.4930ms
- almost all of the slowdown appears to be due to
__call()
routing rather than due to using callabls. WOW
- almost all of the slowdown appears to be due to
- InterfaceObject 12.4068ms
- ArrayMethods 36.6769ms
- ArrayMethodsWithFunctions 32.2399ms
- InstantiateInterfaceObject 8.9591ms
- InstantiateArrayMethods 18.4569ms
- InstantiateArrayMethodsWithFunctions 22.5091ms
Takeway: The approach to code sharing used in Liaison is MORE THAN twice as slow as using the standard approach that uses objects and interfaces
... it's actually THREE TIMES FASTER calling the dependency object directly than it is to use __call()
to call the dependency object.
The reason i use the methods array is ... it's just easier a lot of the time. I don't have to write a bunch of interfaces or implement a class. I can just write a method & use that directly. It's also really easy to switch out one method for another. This makes liaison super customizable.
An additional problem with this is: interfaces make it really easy to properly document what methods do & how they are used. This array-methods approach does NOT make it easy to communicate what the method must do.
Evaluation of what it will take to make these changes
To clarify, there are TWO stages of changes. The first is changing the internal implementation of sharing. The second is to add polish. Here, i am evaluating the internal implementation changes. The polish would come after & I am not evaluating that right now.
- re-implement addon base class (1-2 hours?)
- delete some tests that explicitly test current liaison features (30 minutes)
- ideally these internal changes will not cause any breakage in tests
- re-implement liaison get/set (30-60 minutes)
- constructor changes in every single addon (1-3 hours)
- new package base class? & update constructors (1-2 hours)
- new tests for new internal implementation (1-2 hours)
- In all my foss libs and websites using liaison, create a new branch & bump the liaison version (2-3 hours)
- maybe write a simple bin script that creates a new branch & bumps the version so i can do it automatically, but that would probably be a waste of my time
- Unforseen stuff (4-6 hours)
- potential changes in liaison libraries
old notes (from v0.5)
polish / niceties / fixes
- make
$package
available in a view (being the same package that the view came from) - make new packages not override lia:server.package
- having
addon->name
not matchaddon->fqn
causes it not to be added to liasion... - Redirect addon directly calls
header()
instead of using a hook to modify the response before headers are sent by the server addon. - Ex:
POST /user/register
redirects to/user/register/
which breaks the POST. Maybe allowPOST
to work with or without trailing slash?
Apr 8, 2022
- added dump() method
- server package now adds itself to fqn_addons: This is likely to cause problems as is uses
$this->fqn
in the constructor. So if you instantiate two server packages, the 2nd server package will overwrite ... this is bad. But it's how it is for now & it does not cause a breaking change. - add a default cache dir so it works out of the box
- recently added MinimalServer test for documentation purposes
TODO
- add
no-cache
header to most responses - 3 tests are failing ... fix them!
- my immediate cache invalidation is not working (at least on reedybear.com), so i have to manually delete the cache dir for every css change. fix this!
- Write docs for:
- create a new app
- add a css or js file to the request
- .... stuff
Versions (Dec 8, 2021)
v0.5 (with minor changes) will likely become an official beta. Then after some usage, it'll become v1.0. Probably by June, 2022, but who knows?
- v0.5: Uses
Addon
s instead ofCompo
s. Much more direct access to methods, properties & major overhaul. Internally uses a lot of memory pointers. All addons ARE liaison instances. Packages are too. Lots of other changes. Dec 8, 2021: Under development, nearly ready - v0.4: abandoned ... WAS intended to do what v0.5 is while providing backward-compatability to v0.3 setups ...
- v0.3: abandoned. Uses
Compo
s (Components). A major version ... used->api('namespace:key', $arg1, $arg2)
all over the place ... abandoned dec 8, 2021
Idea (March 25, 2022)
Liaison is confusing because there is so much magic. Liaison holds packages. Packages hold addons. Addons communicate with each other through liaison & through their packages.
There are also settings/configs that can be set through liaison or on an addon directly.
There are global methods which can be directly called on liaison.
There are other things that ought to be inspectable, too - views, routes, resources, idk what else
So the idea is to add debugging features. First, a view (and an associated public route) to display inspection information for all of these.
An integration with code scrawl to inspect an addon class would be really cool. /liaison/debug/class/?name=whatever
And then maybe having certain inspection views display on errors ... like if there's no routes, that could show the inspection for routes.
Exceptions could also be handled nicer. I mean ... every exception could dump liaison debug info, if i want! (seems overkill)
There's also some really weird things, like ... since you don't instantiate addons directly, certain configs have to be instantiated before initializing their package. Idk if that's fixable or properly inspectable ...
I REALLY need to document how to write a custom router & return a route list (need an easy way to make routes for this purpose)
I also need a way to get PACKAGES that don't have any addons ...
PROBLEM (march 23, 2022)
I have to set server.cache.dir
BEFORE initializing the main server
package:
$lia->set('server.cache.dir', $server_dir.'/cache/');
$server = new \Lia\Package\Server($lia, 'server', $server_dir);
Otherwise, compiled resource files do not deliver!!!
Jan 25, 2022: New stuff
- added
code/class/Router/FastFileRouter.php
with an extremely simple and fast routing mechanism for files in a directory - added
code/file/mime_types/*.txt
where there's a file for every extension & the file only contains the mimetype - FastRoute was added to the test server deliver script
... this could be used in place of the current (awful) StaticFile implementation
Known Issues (jan 4, 2022)
- a dynamic portion of a url cannot contain
-
by default. this is BAD ... slugs contain hyphens, silly
Problems (jan 16)
- must explicitly add views for a package like: ... not true ... the dir just needs to be
/view/
& this is not clear-
$view = $lia->addon('lia:server.view'); $view->addDir($site->dir.'/views/', $site);
-
-
$lia->set('server.cache.dir', $dir)
must be called BEFORE the main server package is setup - use
\Lia\Package\Server
for most setups ... but it's not obvious
Jan 15, 2022
- WARNING: when cache dir is not set, now an exception is thrown, instead of just returning false ... somewhere in the cache addon class ... several tests are failing ... I should address this. I might have to roll back. idk
- i attempted toa dd global args to view, but I commented out the code & just didn't finish it.
Dec 17, 2021
- review dec 16 TODOs & CONSIDERs
- add header('Cache: no-cache') to all requests that are NOT static-file requests
Dec 16, 2021
-
DONE view/theme priority (new views always overwrite null-namespace)
-
DONE for
view/theme.php
also addview/theme/*.css
&theme/*.js
-
DONE make
$lia->server
access$lia->addons['server']
&$lia->server->cache
would access$lia->addons['server']->addons['cache']
-
DONE: add
config.json
file to app dir for server-package- DONE: Test it
-
DONE: Add fqn for addons, like
lia:server.cache
that is accessible from ALL liaison objects by that string. Maybe$lia->addon('lia:sever.cache')
... -
DONE: fix confusion around
addon->addon_name
&addon->name
;- removed
addon_name
and only usingaddon->name
now
- removed
-
DONE??: fix
_lia
scoping. The lia object passed to views is NOT the root object.- i couldn't reproduce the bug with my test. The bug came from taeluf.com
-
TODO: Add a logging feature! Just to log messages to a file.
-
TODO??
debug
feature to help inspect addons, properties, and more... ? -
TODO:
$this->depend('lia:server.cache')
feature (or$this->depend(\Lia\Addon\Cache)
?) -
TODO: review disabled tests & get them passing or remove them
-
TODO: Add robust setup-events for packages/addons
- all addons within package are loaded
- all other packages are loaded
- everything is ready
-
TODO: Add global objects ... example:
mdblog->blog
would fit well atlia->blog
-
CONSIDER: Does server package REALLY need the default server package to be added in order to function at all?
-
CONSIDER: Should
fqn_addons[ns:package.addon-name]
also have null-ns, like views do? (leaning yes, but let's wait til I need it) -
CONSIDER: Removing
name
from constructor for addons, package, lia. Subclasses generally don't need them ... but then again the server package needs it. -
CONSIDER: Should
package->name
be overwritten byconfig.json[name]
?
Dec 15, 2021
- add
onPackageReady()
to addons, called by\Lia\Package->ready()
, which is NOT called during the package constructor, but IS called during the Server package constructor - I was having issues with
_lia
scoping ... (maybe see mdblog? idr) - I want addons to be accessible via
__get()
&__set()
-
Server
package should default it's name toserver
- Should hook become part of liaison proper? (i lean yes) also maybe error & cache? No, cache is thicc. Error logging, maybe? Maybe
Dec 14, 2021
- TODO: Add a logging feature! Just to log messages to a file.
Dec 10, 2021, end of day
- I was last working in MdBlog addon ... go look at that
- Review Server PACKAGE and ensure some simplicity
- should the server ADDON be a package? (leaning no)
- need a way to have addons always be stored in their namespace-form, like
lia:server.hook
orlia:server.seo
, etc... So I can have a guaranteed way to reference an addon. Probably just use those simple string keys. Could use anaddon()
function to retrieve them from current data structuer? - i'm not in love with how I set up addons ... idunno ...
- name/addon_name is still a mess & just needs some thinking & review & updating
Dec 7, 2021
Main:
- I was working on the server integration test. It is failing, only because the test needs updated. Parts of getting this working:
- Wrote
code/Server.php
(server PACKAGE) - add
addDir()
to view addon - add
dir_to_patterns()
to router addon - messed with the addon nesting in package (maybe in lia too?)
- fixed the built in theme view & error/header view
- wrote test/Server/deliver.php
- wrote test/run/Server (needs corrected)
- Wrote
Issues:
-
Package->name & package->addon_name & Package::__construct($lia, $package_name)
... confusion, uncertainty, duplication ... the nesting of->addons
is ... idk. - need unit test in router for dir-to-patterns & it's helper function(s)
-
PackageAddonIntegration
test is failing. Several Liaison tests are still disabled. - the ExceptionCatcher is ... bad
- in
set_error_handler
, i need to callExceptionCatcher::throw(new ErrorException(...))
, instead of re-throwing there
- in
- need to test view conflicts
Dec 2, 2021
- Error header message test is passing because I added an explicit print to the test theme view. I don't know if this is how I want it to work. I need to review this with a fresh mind. Also, the display is checking
$this->lia->addons['error']->headerMessage
which ... is probably the wrong way to do things.
Dec 1, 2021
- Error Addon: Started on it ... one test passing ... needs some TLC to get things sorted
TODO
- Error addon:
- Review & Update
- Server addon:
- test the hooks
- test deliver() method?
- general refactor so it just ... makes more sense
- implement Resource addon tests DeliverJs & DeliverCss after Server is re-done
- Check Server integration for:
- Resources
- ResourceSorter
- Autoload
- completely get rid of the response & request objects (& maybe Route object)
- refactor router
- refactor server
- refactor resources
Nov 30, 2021
- Resources addon changes:
- Remove
forceRecompile
config (only usinguseCache
) -
recompileJsAfter
& css is removed (these weren't implemented anyway!) - refactor ??
- Remove
Nov 29, 2021
- refactor seo addon
- refactor (slightly) & clean up (massively) and document router addon. Add new (simpler) router addon tests. Separate old router tests into RouterOther tests (bc they are sloppy & I don't want to refactor them).
Nov 26, 2021
I feel a bit uneasy about the work I did today. Everything is working - tests are passing ... but I just feel like some things are undone. I think I want to review, at least, the router addon & look for any api()
calls, at the very least.
I also may want to add additional tests - like testing that seo & router work with package & work with liaison -> package -> addons
setup
- Seo Addon
- converted to addon
- tests passing (fixed one old one)
- no exception catcher
- Router Addon
- all tests passing (including ones that I had failing previously)
- no exception catcher ...
- converted to addon
- Cache Addon
- added an exception catcher case
Nov 24, 2021
- View addon
- all tests passing
- added to exception catcher
- docs written (docblocks)
Nov 23, 2021
NEXT I have some confusion about how to handle scanning?? Or something. Idk. It doesn't matter.
Just working through additional component's one at a time, turning them into addons. Let's keep most changes simple so I can get through it all asap & start using the new system in prod & adding features
DONE
- add hook handling to exception catcher
- add scan() method to liaison
- add prefix integration to hook
- add hook to package test
- move GlobalParam to old folder (likely will not use)
- add prefix/scan test class
- add OldTests test class
Nov 18, 2021
5:00pm: package integration test written. cache & autoloader both working nicely with it. Need to work on next addon, then update package integration to include it.
Latest: I'm working on prefixes inside the hook addon class code/addon/Hook.php
-
IDEA: Scanner should be an addon &
depends
feature will make it so easy to use- NO. Scanner is fundamental to Liaison.
-
LATER: create a liaison test that creates multiple packages so that they work together.
-
LATER: Add prefix scanning for Hook after implementing it.
-
LATER: (i disabled the tests) The cache class & tests are all passing.
AddMethods
&AddDotMethods
are still failing on the Liaison test. I think I removed nesting of methods on Monday?? This will need addressed, but I want to focus on the addons and making sure new Lia provides what they need, instead of getting caught up on what Lia "should" do. So I'll revisit this decision later after I've written more tests & used Lia more -
LATER: (i disabled the tests) Package tests
AddAddonsPackageAddons
&AddAddonsPackage
are failing because I used to have$lia->addons['ns']['package'] = $package
, but I removed it ... because it caused a test to fail & it just didn't FEEL right having it there. But now I see / remember why it was. I don't know what I prefer. Maybe add apackages
property toLia
to hold packages. Maybe keep the package in the addons list. I don't know. I'll write more tests, see what feels right in practice & re-visit this decision. I will not fix the tests until then. -
NOW? I want to start a new Package class who's entire job is to setup addons & invoke them. I want a base package class for use on any Liaison setup, then a Server package that ties together all the built-in components into a web-server (which is kind of what the old Package does).
-
DONE I want to rename
configs
toprops
because ... I think it is more intuitive
Nov 15th, 2021
Success! I re-wrote the autoloader & autoloader tests. I started rewriting cache & its tests. Cache is successfull for everything I've re-implemented. Notes:
- main cache: set() get(), write(), read()
- this is a new feature to set key=>value pairs
- it uses the config stack that exists from liaison & essentially writes $lia->configs['cache'] to disk as php
- classic file cache: I have not touched it yet & its tests are currently failing
BIG new thing
I have properties declared on both Autoloader & Cache, which each of them use directly. In their constructors, each addon is setting those properties to $addon->prop_name = &$this->configs['prop_name']
. I REALLY like this so far, bc it makes a tree of all the values that are set & need to be set. I have no idea about the performance ... But I imagine it's not too bad.
Next
- finish updating the cache tests & cache class. I do want to keep the ability to cache files. The code needs re-factored & other than that ... I think it's basically fine. I want a
cache_file
method on liaison as well.
How to think about Liaison
Liaison
is a singular object that holds all shared information & methods & addons
Addon
s are objects that provide specific functionality.
Package
s are objects that set up addons on Liaison
Does Liaison officially recognize packages? I think yes ... I think so
Do Addon
s officially recognize packages? Not normally ... I don't think so
Do Package
s officially recognize addons? Yes, I think so. Kinda have to
So the entire thing exists to server addons. Addons need to be able to communicate with other addons. Packages helps set things up. Liaison does the actual communication. User-land code ALSO needs to be able to communicate with addons.
Repeat:
- Addons provide functionality and need to communicate with (and depend upon) other addons
- Packages provide utility that makes it easier to set up multiple addons
- Liaison is the object which provides communication featurse between addons
- User-land code uses Packages to setup addons & uses Liaison to access those addons.
Note:
- Addons are simply a way of packaging features together. Ex: Cache addon has a suite of functions to handle caching. Alternative Ex: Several cache functions exist & user-land code just registers them to Liaison, no addon needed. This is NOT the intent, but it's how it ought to work.
So, how do I provide global access to methods & properties?
-
$lia->method_name();
calls whatever method was registered -
$lia->methods[method_name]();
-
$lia->prop_name
gets whatever value is registered at$lia->props[prop_name]
-
$lia->props[prop_name]
How do I access packages & addons?
-
$lia->addons['name']
gets whatever addon is registered -
$lia->packages['name']
gets whatever package is registered -
$lia->packages['name']->addons['name']
gets an addon from a package
How do I get namespace access to methods and properties?
-
$lia->get('ns.name.prop')
gets$lia->packages['ns']->addons['name']->prop
where->prop
is a real property on the addon?
How does an Autoloader addon access a cache addon?
-
$this->lia->cache()
to call the global cache method -
$this->lia->call('pkg.addon.cache')
to call a specific addon's cache method -
$this->lia->packages['pkg']->addons['addon']->cache()
to call the specific addon's cache method - shorthand:
$this->lia->addons['cache']->cache()
to get the global cache object & call its method
Features
Liaison object has:
- global methods (set by anyone, normally by addons)
- global objects (set by anyone, normally by addons or packages)
- global properties (set by anyone, normally by addons or packages)
- namespaced methods
- namespaced objects
- namespaced properties
So if I have an autoloader class that needs configs & cache, it could access those via:
$lia->configs->methods();
or by $lia->config_method
where the config objects' method has been explicitly set to liaison
What are my actual needs?
- one object from which I can access:
- all packages
- all addons
- all root-set properties
- all root-set methods
- Does it need to support:
- $lia->get('addon.propname')?
- $lia->call('addon.methodname')? Is this good enough:
- $lia->addons['name']->method();
- $lia->packages['name']->addons['name']->method();
- $lia->addons['name']->property
- $lia->packages['name']->addons['name']->property Can i THEN add convenience methods?
- $lia->set('pkg.addn.property', 'value');
- calls $lia->packages['pkg']->addons['addn']->property = value; What am i doing currently?
- $lia->set('pkg.addn.property', 'value');
- $lia->configs['pkg]['addn']['property'] = $value;
- $package->configs === $lia->configs['package']
- $lia->addons['pkg']->addons['addn']->property = $value;
- $lia->call('pkg.addn.method',$arg1,$arg2)
- $lia->methods['pkg']['addn']'method'
- (would be) $lia->addons['pkg']->addons['addn']->method($arg1,$arg2);
v0.5
v0.5 is like v0.4 except I'm abandoning the entire backwar-compatability idea. I'm going to re-code tests & addons using the new setup instead of trying to make it all fit seamlessly with the old setup.
So v0.4 branch is dead. It will not be developed further, unless I change my mind after working on v0.5 a bit.
Next:
Think about my approach to this refactor. I've spent several hours and a lot of energy making everything backward compatible. It's kind of a nightmare. So I'm not entirely sure how I want to go about things. I may go away from the "constant BC" route & just dive full-in. I really don't want everything to break at once, because fixing THAT will be a nightmare. I WANT to go through pieces of this library one at a time, switching things out as I need. Fuck. I might rewrite some tests too. Idunno. Its the end of the day and it all sounds terrible lol. Need to re-asses with a fresh mind.
I'm also having a hard time understanding how the backward compatability actually benefits me. I think it's so I can switch a site to the newest liaison & have it keep working ... but as long as it's using the BC liaison object and the old components ... I just have to keep both around! Either way, I'm glad the original Liaison object is done for. So freaking glad
- meh ... "Function name must be a string": Running into this issue because there is a null value at the location a method should exist. Why/how does that null value happen? Can I catch the error with my fancy exception handler?
- Start turning the components into Addons, one at a time. They will subclass liaison. It will be interesting.
Notes:
- package is a subclass of addon & addon a subclass of Liaison, but they have significantly different needs, so the constructors don't call parent::constructors. Instead they call
$this->copy()
which should be a bit more consistent in how it operates between liaison subclasses.- perhaps package should not be a subclass of addon?
State
- DONE setup by-ref properties
- DONE add methods
- DONE add api()
- DONE add get/set
- DONE test all of the above
- DONE add addons management
- DONE add
->_lia
for root liaison object &->lia
for parent liaison object - DONE start ExceptionCatcher
- DONE get package tests passing (see
Other/OneOffTests.php
) - DONE Get the Scanner tests passing
- There are two scanner tests that are NOT passing. Focus on those??
- Setup the new scanner trait &
use
it onLia
(see notes below)
- DONE Start passing individual component tests (one at a time. take it easy. take it slow.)
Re-testing with LiaBC class
- DONE some tests are stalling due to re-addition of
lia:config.default
api (seeLiaBC
where this api is added to liaison)- FIXED
OneOffTests->ComponentsAndRequestLifecycle
- done There is an issue with
cacheFile()
getting anull
dir ... but only for thecss
resources, not thejs
- done spawns from
getHeadHtml()
... it is a MESSSSSS
- done There is an issue with
- FIXED
Redirect->GoTo
- FIXED
Error->ErrorHeader
- FIXED
Error->ErrorPage
- FIXED
- FIXED
OneOffTests
kind of seem like a nightmare ... uhh idunno - WILL NOT FIX
Exceptions
test are failing & I don't think I'm going to fix it. - DONE all the component tests are passing, except for the ones that use a non-bare liaison ... so the only issue now is getting package to work with LiaBC.
- DONE
Other/LiaisonApi.php
works. I disabled a couple mediator tests because I don't use mediators ANYWHERE, so it's not worth fixing - DONE
Other/OneOffTests.php
: These are significant integration tets, so these need to go later. - DONE
ScannerTrait
(test/CompoTrait/Scanner.php
): The old implementation is SUCH a mess. The whole thing is terrible. I think it may be worth rewriting the scanner from scratch with almost no features. It should be VERY simple. The old version uses$lia->api(...)
to call the prefix handler method... I want to have methods that accept callables for particular purposes (like registering an event). When a prefixed-method is found, it should be passed to that setup-function (event registration, etc).- I made a new scanner trait with minimal modification to sustain backward compatability.
ScannerTrait: New Design
What does it need to do?
- have a list of prefixes
- build an array of methods that have those prefixes
- pass the methods (
[$this, 'method']
) to the functions responsible for setting up those prefixes
How do I do it?
-
public array $prefixes = ['on'=>[$event, 'prefix_setup']];
-
get_methods($this)
...substr($method_name,0,$prefix_len)==$prefix
...$methods = [$prefix=>[list_of_methods_on_this_object]]
-
foreach $methods as $prefix=>$method_name: $this->prefixes[$prefix]([$this, $method_name])
- usually
$this->prefixes
will refer to the root liaison's array of prefixes (because of$lia->copy()
). BUT any lia object (addons/packages, etc) could have it's own array of prefixes that is not referencing the root.
- usually
v0.4 Goals
Approaches to Liaising
- by-reference properties
- via method calls on the Addon class that remap to Liaison methods
Step 1: Prototyping by-ref
I want to prototype a new system for having addons call liaison methods. I'm tired of $liaison->whatever...
& want this to be more streamlined. I want to try copying liaison properties by reference to make it easier.
Example:
$lia = new \Liaison();
$package = new \Lia\Package($lia);
//$package->__construct() will call
// $this->copy($lia)
// $this->configs = &$lia->configs;
// $this->configs['namespace'] = [];
// $this->configs = &$this->configs['namespace'];
$addon = new \Lia\Addon($package);
// $addon->__construct() will do:
// $this->copy($package) (where packge is a liaison instance)
// $this->configs = &$package->configs;
// $this->configs['addon_name'] = [];
$this->configs = &$this->configs['addon_name'];
So rather than modifying anything, I think I should start with a new class & just try out these basics.
Major Changes Overview
- Change "compo" to "addon"
- Add a system for addons to call liaison via
$this->liaison_method()
- MAYBE make
addon
s into instances of liaison & use by-ref properties
- MAYBE make
- turn
Package
into anaddon
- MAYBE Move 'event's onto Liaison, but call them
hook
s. - MAYBE add dependency hooks onto Liaison proper
- MAYBE add scanning onto Liaison proper
Extended notes / thoughts
Rename compo to addon. Add methods to make them work more friendly with liaison. Like get, set, add method, add prefix. Basically remap all the core liaison functions to auto-include ... Namespace & name.
Turn package into an addon. It will all be much easier to understand then. Then do i add addons to liaison? Does liaison auto-setup an addon? No. The addon sets itself up. This means different types of addons csn be made. Most of mine will be subclasses.
So then package is an addon & basically it sets up dependent addons for certain sub-directories of a dir given to it.
Liaison should have it's own property for addons. A key/val array. & a method to add an addon. The main addon class will call that in its constructor.
Package is an addon but it will contain other addons & provide features for easily setting up addons. Package will probably also host it's own array of addons. But then do addons IN the package have to also call the package's method?
Maybe liaison can have hooks on its get/set methods, then package can just copy when addons are added. This is a performance hit through constant branch checking. I think it would be far more efficient to use a liaison subclass that routes all the methods liaison has, allowing the package to be a liaison instance & the addons it initializes to use it (the package addon) as liaison.
So an addon then would do: $lia->addAddon($this, get_class($this)); which invokes $package's $lia->addAddon($addon, $namespace.':'.$addon_name); call which invokes actual $liaison & does $liaison->addons[$addon_name] = $addon; this all.happens during the addon's constructor. In this chain, package can also maintain it's own addon array.
Should events go on liaison? No i don't think so. Just prefixes, methods, and apis.
Then in my addon's constructor, it will do $this->addMethod('ownMethodName'). $addon->addMethod($methodNameForLiaison, $ownMethodName=(defaults to arg1)), which will call package's addMethod() which roures directly to liaison.
Shooot. What if they all access their own properties directly without any redirects by referencing memory addresses?
So package would do $lia->configs['namespace'] = [];. Then do this.configs = &lia.configs.'namespace'; so the package's configs directly reference the variable held in liaison. Do the same for addons?
Maybe add a copy method to liaison that takes in a liaison object & does the by-ref thing. Package maybe would override copy, call the parent, then do it's own setup. Or just call copy, then do its set up.
Now that package is setup by-ref, it will construct the addons & pass itself to the addon. So when the addon does this.methods[name] = this, it's setting it to package's ref of methods prop. (Errr ... Maybe make methods completely flat, but have an api array that is nested.
So then ... Views. Do i just assert that onto liaison? Like lia.views[name] will work? Perhaps i put it in the namespaced configs & in the flat.
Make a PackageAddon class that responds to hooks in the package. Hooks could be a very simple trait ... Idunno. Maybe hooks/events belong on liaison. ...
Server requires hooks. Some addons can't do their setup until dependent addons have already been setup, which requires them to hook on the dependents or ... Or on the package. I like hooking on the dependents. That means each depended upon addon would have to execute the hook when it was done setting up.
It would make sense for certain addons to broadcast when they are ready. The server addon might respond to the public dir addon broadcasting that it has set up a public dir. And that it's about to. Maybe the server addon could stop it from scanning a public dir if a cache of the routes is recent enough. It makes sense for the server to be responsible for state management while a separate addon is responsibke for scanning & setting up a public directory. Tbh, package is probably where public dir setup belongs. I could add it to router though. Idunno. I feel like routers responsibility is already complex enough that i don't want to add things to it.
Latest
- updated
Route
object tois_string($target) && is_file($target)
, soisFile()
doesn't give error when it's non-string target - added basic url normalization to the server component. it needs refactored.
Current
- attempted to add
-
&:
to valid chars to separate dynamic values in a url. But a couple tests are failing, Idk why & it needs to be troubleshot - add https://github.com/matthiasmullie/minify as optional dependency
- Tried
cerdic/css-tidy
and had problems
- Tried
v0.3-candidate Plans
-
default()
should be able to receive an array to set multiple defaults at once - Delete all exceptions except for my base exception
Get/set
Can I do a readonly
feature?
I may be able to condense some of my simple components into a single one since there's no more data structure management.
- add
get
&set
to Liaison Proper, doing away withConfig
component - Use
$lia->set()
&get
to store packages, compos, and basically anything that's currently being managed by a single component- Router still needs its own internal data structure
- add
arget()
andarset()
for getting/setting to an array.-
arset('namespace:some.key', 'keyInTheArray', 'valueForKeyInTheArray')
-
arget('namespace:some.key', 'keyInTheArray')
returnsvalueForKeyInTheArray
-
get(namespace:some.key)
returns the array containingkeyInTheArray => valueForKeyInTheArray
-
Events
Since Liaison's goal is to, well, Liaise... I think it should do events, too. It can already to 1-to-1 method calls & I'm adding 1-to-1 property setting / getting. So it would make sense to be able to emit an event. Here's the implementation idea:
-
$lia->emit('namespace:Event.Name', arg1, arg2, arg3)
- Internally, it creates
new Event($lia, arg1, arg2, arg3)
. then$event->emit()
- & this way, the event gets listeners from Liaison, then goes through all of them. & each events listener gets an instance of the event object, plus all the passed args. Any values can be set directly to the event object
- You can also directly do
new Event()
... & emit it yourself, without the helper method
- Internally, it creates
Code Work
Next
- add error reporting when a package directory does not exist.
- (current) Error Component
- Working on error_goto.
- Need an Error Route (maybe as a public file, idk. Might make it configurable)
- Need to setup test. I started the test, but can't really wrap my head around how to do it.
- Working on error_goto.
- Improve error views (header & page)
- Middleware & Routing
- Add a 'handleRequest()' method that allows any component to handle a request
- How does the web-developer decide who's handling requests? The
middleware
approach might be best.addMiddleWare()
&removeMiddleWare()
could be used by theServer
component... It might use a couple if statements to determine which middlewares to add. But the flow would be the same regardless.
- Caching:
- Routes from public files (Router)
- Classmap of a package (autoloader)
- Cleaner
Route
interface/object - Cleaner
View
interface/object
Latest
- Refactored Scanner to have only two methods & be more efficient. Updated all tests so they're now passing
-
Router
component can have additional routers added to it for custom routing. - Add
append
method to Config component - Renamed package setup functions to
setup_the_thing
& addedsetup()
function to move setup out of the constructor. - Add namespaces to the view component
- Modify package to use namespace when calling view component
- Remove 'lia.packages'. This was a mistype & should have been 'lia.package' all along
- Convert package list to use namespace instead of name
- Separate SEO methods/api from
Resource
compo - namespaced apis. converted
api('lia.action', 'handler',...$args)
toapi('lia:action.handler', ...$args)
- namespaced configs with consistent naming like
lia:componame.configName
. - Ensure there is a
default()
call for every config
Documentation work
Next
- Review property docblocks in Liaison class. They don't match with the api namespaces refactor.
- Continue Docblocking as marked below (in class/Objects/)
- Don't forget the
Objects/ViewCallable.php
: Need to review this when I'm doing theview
component - Write Markdown documentation AFTER docblocking is done
- Write examples as tests & import
Latest
- Docblocked everything except compos
- Updated docblocks on Liaison methods to match api namespace refactor
Things that need to be in markdown documentation
- Specify your package's
namespace
inconfig.json
. This is separate fromname
. - List of available configs
- Full api reference for
code/class
andcode/core
- Featured API Reference? For only listing featured methods & classes
- TODO reference file (grouped by file name in a single markdown file)
- All events & the paramaters they pass
Docblocking status
- Liaison.php
- Mostly good
-
api
methods (addApi
,addApiMethod
, etc...) are not well documented. Since I want to remove$handler
, I'll probably wait on that. - Some things are a little under-documented, but the method-signature and the short function bodies... makes it not that big a deal
- Not
@tag
ged very well
- Compo.php
- Well documented
- @featured & @tag pretty well
- Package.php
- Pretty well documented
- Not sure about my
@tag
s. There are@tag setup
&@featured
. I think there could be more organization there.
- CompoTrait/
- Scanner.php
- Docs pretty good.
- trait needs some rewrite (thus docs will, too)
- Only the class has
@tag internals, component
... Idk.
- Scanner.php
- Exception/
- Base.php
- Wrote @todos.
- Nothing really needs documented here. You just create an exception
- *.php
- I plan to delete the other exceptions & improve BaseException with extensibility. So... No. Not documenting these
- Base.php
- LiaisonInterface/
- LifeCycler.php
- @deprecated & @todo delete, because its not in use far as I could grep
- PackageLifeCycle.php
- Documented nicely. But documentation is nearly identical to documentaiton on
\Lia\Compo
for these methods. Perhaps I can remove identical docs from compo.
- Documented nicely. But documentation is nearly identical to documentaiton on
- LifeCycler.php
- Objects/
- IView.php
- Documented, some @todos
- View.php
- Well Documented, some @todos
- Request.php
- Well Documented, very basic class
- Response.php
- Reasonably well documented. Some @todos
- Route.php
- Adequately documented... bad class.
- No tags... I might want tags
- ViewCallable.php
- TODO <- There is no structure. It's all setup by the View component, I think. So its not well setup for documenting
- IView.php
- Utility/
- ClassFinder.php
- Barely documented, because it comes from my Utility repo. So its fine.
- DotNotation.php
- documented well enough. No tags
- FancyClosure.php
- documented well enough. No tags
- Files.php
- Documented well enough. No tags
- StaticFile.php
- Documented well enough. No tags
- ClassFinder.php
- ../core/
- Has not been started
Future Work
View Getters
The base View Component will implement a view() method. This view() method will loop over all active view_getters & call getView() on each of them. The returned view will be an instantiated class with a __toString()
method. Exactly one view getter must return a view. Each view getter MUST support namespaced view names.
- Phad templates & Lia views will both be accessible through
$lia->view()
. - Lia\Compo\View will
- implement a view getter
- have an add_view_dir($dir, $namespace, $args) function that adds a dir for PSR-4 style view-name loading
- have an add_view_callable($callable, $fullyQualifiedViewName, $args) function to explicitly add a callable as a view
- have an add_view($dir, $fullyQualifiedViewName, $args) fucntion to explicitly add a single view
- this is already implemented
- Phad\Compo will
- implement a view getter
- have an add_view_dir($dir, $namespace, $args) function for psr-4 style view loading
- Some Future View Component will
- implement a view getter
- have an add_whatever function to add whatever.... to be later retrieved by the view getter method