Any technical issue with capitalized component directories? (core/components/MyCompontent)

Some discussion here:

Are there any technical limitations or just a standard we as a community want to stick to? It seems like with 3.0 we introduce Namespaces which are capitalized or CamelCase. Should the directory match the namespace capitalization?

I don’t envision any technical issues from this, but it is certainly a deviation from what’s commonly done.

Even for 3.0, my expectation would be that a namespaced class MyPackage\Foo translates to core/components/mypackage/src/Foo.php - core/components/mypackage/src being the all lower case prefix or path to the root of the namespace. The MODX namespace would also be lowercase mypackage. That’s just how it’s always been done, though. Not a technical rule.

I would propose keeping that rule to avoid the insinuation that core/components/MyPackage might be autoloadable as MyPackage, which in reality that’s core/components/MyPackage/src.

This is also what the MODX 3 core does: the path to the namespaced directory is core/src (all lowercase) which is mapped to the MODX\ namespace, after which we follow the casing of the class names/paths according to PSR-4.

(Unless, of course, we decide to add a global autoloader which makes an arbitrary Extras\MyPackage\MySnippet available from core/components/MyPackage/MySnippet.php without it having to ship with its own autoloader or addPsr4 call…)

1 Like

One spot that’s a little confusing is Processor classes. But I guess the directory structure underneath is irrelevant. It just made sense to me to match them.

Example Processor class: ExtraBuilder\\Processors\\Update
Directory structure: core/components/ExtraBuilder/src/Processors/Update.php

But really the directory doesn’t matter as it’s just checking for an autoloadable class, and if found, using that.

The second question related to this is should the namespace record in MODX be all lowercase as well? That is then a little confusing as well since the namespace in your classes will be Uppercase and not match.

The convention for the MODX namespace is indeed lowercase, because the (transport/model) package name is also lowercase and package names have a very strong correlation to the MODX namespace. There could in theory be technical issues with non-lowercase packages in package providers (MODX, modmore, modstore) but as the convention has been lowercase for over a decade I’m not sure if anyone has tried.

Until there is a technical reason to diverge from the convention, I would quite strongly recommend keeping the lowercase package, MODX namespace, and components directory. Then a lowercase src directory which correlates to your CamelCase/PascalCase PHP namespace and classes.

While using similar terminology, MODX and PHP namespaces are very different things so keep those separate.

Package names can be mixed case, as can their elements and resources, but in my experience package filenames, directories, and namespaces are always lowercase. AFAIK, the only time I’ve ever violated this is when a package includes some utility like Guzzle, that doesn’t follow those conventions.

I am not aware of any component namespaces (MODX namespaces, not PHP namespaces, which are totally different) being mixed case? Do we have examples of this?

My latest rebuild of ExtraBuilder uses “ExtraBuilder” as the component directory and component namespace. That’s what originated the discussion then on standard convention and technical limitations if there were any.

I think the only technical impact was on the CMP index routing. The class had to match that capitalization:

@markh @opengeek
Couple questions around the meta map output in 3.0. The $xpdo_meta_map that is generated also has “namespace” and “namespacePrefix”. Those are built directly from your “package” value in your schema. and the prefix you specify when calling parseSchema.

In MODX 2, you could specify a package value of mycomponent.src.model and then when calling parseSchema, pass the directory as MODX_CORE_PATH . 'compoents/';. This would then generate your class files in /core/components/mycomponent/src/model/.

In MODX 3, you can no longer use dot separations to specify the directory. Also, any value you specify in the Package field is set as the namespace in the map.

Since we are registering our classes with the autoloader, is this meta map namespace ever used? What “namespace” is this?

From digging into the addPackage functionality, I don’t see that the “namespace” is ever used. The “namespacePrefix” is critical since that is used for the self::getLoader()->addPsr4($namespacePrefix, $path);.

The only difference I see from using addPackage vs. using addPsr4 in your bootstrap file is that add package also adds your model classes to the $this->classMap. But it seems to work fine without that.

So, after that I guess my questions boil down to two:

  1. What is the “namespace” used for in the meta map? What does it represent?
  2. Is using addPackage for object classes more efficient or better since it adds to the classMap?

Thanks!

It is used in Transport packages and the generator but may be used in other ways in the future or by custom code.

Using addPackage is absolutely required to properly add a model. Otherwise, various features of xPDO would not work properly. addPackage calls addPsr4() on the loader, but addPsr4() on the loader would never be able to add the classes to the xPDO classmap metadata.

@opengeek Thanks for the reply on that. After playing around a little bit with it, I see that it is generated to the PHP Namespace in the class files. Later I’ll get this into the docs, but in case someone finds this looking for details.

Example Schema package:

<model package="MyComponent\Model\" baseClass="xPDO\Om\xPDOObject" platform="mysql" defaultEngine="InnoDB" version="3.0">
  <object class="MyClass" table="myc_class_table" extends="xPDO\Om\xPDOSimpleObject">
...

Then parsing… not intended to be a complete example, but covering the differences in MODX 3.0.

<?php

// Get the manager and generator
$manager = $modx->getManager();
$generator = $manager->getGenerator();

// Parse the schema to generate class files
$generator->parseSchema(
  MODX_CORE_PATH . 'components/mycomponent/schema/mycomponent.mysql.schema.xml', 
  MODX_CORE_PATH . 'components/mycomponent/src/',
  [
    "compile" => 0,
    "update" => 2,
    "regenerate" => 2,
    "namespacePrefix" => 'MyComponent\\'
  ]
);

Directories built in core/components/:

mycomponent/
  src/Model/
    mysql/
      MyClass.php
    MyClass.php
    metadata.mysql.php

The generated class files have the package value at the top as their namespace, and then follow the directory structure under mysql.

First class file under src/:

<?php
namespace = MyComponent\Model;

And then the files under mysql/:

<?php
namespace = MyComponent\Model\MyClass\mysql;

I think, it will result like that:

mycomponent/
  src/Model/
    mysql/
      MyClass.php
    MyClass.php
    metadata.mysql.php

and maybe you should add

$manager= $modx->getManager();
$generator= $manager->getGenerator();

at the beginning of your snippet, to make it complete

Edited based on your feedback. :+1:

1 Like