Class Not Found Error with custom Class Concrete5.8 - concrete5

New to C5 and Namespaces. Trying to add my own class, but keep getting error that it can't find the class, even though PHPstorm seems to know where it is. Seems simple enough but I'm missing something.
Path to class application/src/cpi/funcs/Utils.php
Class
<?php
namespace Application\Src\Cpi\Funcs;
defined('C5_EXECUTE') or die(_("Access Denied."));
class Utils
{
public function Getcreditcard_year($y = 10)
{
$currentYear = date("Y");
$currentYearVal = date("y");
$year_list = array();
for ($i = 1; $i <= $y; $i++) {
$year_list[$currentYearVal] = $currentYear;
$currentYear = $currentYear + 1;
$currentYearVal = $currentYearVal + 1;
}
return $year_list;
}
}
?>
Code in View
<?php
use Application\Src\Cpi\Funcs\Utils;
$years = new Utils();
//$years->Getcreditcard_year();
?>

A few core features have been updated in Concrete5.8 that change the way you should use namespaces. You have two options to go about this.
Option 1:
Concrete5.8 has had some minor updates to its core Routing which now uses application/src/concrete/ instead of application/src/ to search for your custom classes, and is triggered to look in to that folder when a class has \Application\Concrete\ in its namespace. Basically, you would do the following:
Class
Update the namespace of your class and move it to application/src/Concrete/Cpi/Funcs/Utils.php
<?php
namespace Application\Concrete\Cpi\Funcs;
class Utils{
...
}
Code In View
use \Application\Concrete\Cpi\Funcs\Utils
...
Option 2
Re-enable the legacy Routing to read in application/src/ when \Application\Src\ is used in a class's namespace.
C5 core team have created a function to enable legacy namespaces, enableLegacyNamespace(), which you need call during the bootstrap. I've added the coded in my application/bootstrap/start.php file. Not sure if it is the best place to enable it but it works. The file now looks like this:
<?php
use Concrete\Core\Application\Application;
use Concrete\Core\Foundation\ClassLoader;
/*
* ----------------------------------------------------------------------------
* Instantiate concrete5
* ----------------------------------------------------------------------------
*/
// This line allows us now to use \Application\Src\ in our class namespace
ClassLoader::getInstance()->enableLegacyNamespace();
$app = new Application();
...
Using this option means you don't have to modify or move your class and can use as you have it set up currently.
Just sharing some advice
I have my concrete5.8 sites to use both options. For my custom classes, I use option 2 but when I want to overwrite or expand a core class I use option 1 and place the file inside application/src/concrete/ and use the \Application\Concrete\ namespacing.
e.g.
Say, I want to extend the core PageController class. First, I create the php file and add it under application/src/concrete/. The file path would look like this: application\src\Concrete\Page\Controller\PageController.php. I am trying to mimic the folder path of its core file which is found in concrete\src\Page\Controller\PageController.php.
Class
<?php
namespace Application\Concrete\Page\Controller;
...
class PageController extends \Concrete\Core\Page\Controller\PageController
{
...
}
Then overwrite the core alias pathing with your custom alias inside application/config/app.php so concrete knows to read from a custom class instead:
return [
'aliases' => [
// extend the page controller class
'PageController' => '\Application\Concrete\Page\Controller\PageController',
];
Hope this helps.
Cheers.

Gianni's answer is still valid on c5 8.5.1, incase anyone is wondering. The correct path is application/src/Concrete, not application/src/concrete. If the c is not capitalized, c5 will through an error for not being able to find your class.

Related

excluding tables with setExcludedDoctrineTables when loading fixtures with liip TestFixturesBundle

I'm trying to use Liip test bundle to load fixtures from code using the loadFixtures() method from FixturesTrait
However, I need to exclude the RESOURCE table that I don't want to be dropped in the process. If I understand correctly, this should be easy using the setExcludedDoctrineTables method according to the doc https://github.com/liip/LiipTestFixturesBundle/blob/master/doc/database.md
Unfortunately, when I run this code, the table RESOURCES gets dropped with all the others.
Can anybody see why ?
not sure if that's relevant but I'm using a mysql db in a separate docker container.
<?php
namespace App\Tests\Controller;
use Symfony\Component\Panther\PantherTestCase;
use Symfony\Component\Panther\Client;
use Facebook\WebDriver\WebDriverBy as By;
use Facebook\WebDriver\Exception\TimeoutException;
use Liip\FunctionalTestBundle\Test\WebTestCase;
use Symfony\Component\Panther\PantherTestCaseTrait;
use Liip\TestFixturesBundle\Test\FixturesTrait;
use App\Repository\UserRepository;
use App\DataFixtures\UserFixtures;
use App\DataFixtures\AccountFixtures;
abstract class AbstractPantherTest extends WebTestCase{
// use trait so we can combine Liip and Panther features
use PantherTestCaseTrait; // this is the magic. Panther is now available.
// provide fixtures loading feature
use FixturesTrait;
// #var Symfony\Component\Panther\Client
protected static $client;
//Initialize the test case
function setUp():void
{
static::bootKernel();
if(self::$client === null){
self::$client = self::createPantherClient(['browser' => PantherTestCase::FIREFOX]);
$this->setExcludedDoctrineTables(["RESOURCES"]);
$this->loadFixtures([
UserFixtures::class,
]);
// retrieve the test user
$userRepository = static::$container->get(UserRepository::class);
// retrieve the test user
$testUser = $userRepository->findOneByUsername('Administrator');
// simulate $testUser being logged in
self::doLogin($testUser->getUsername(), 'xxx');
}
}
}
Answering my own question as I just found out the issue. Sometimes a good night of sleep is all you need :)
So this code is actually working. The table RESOURCES got dropped because the setUp method was redefined in the concrete class implementing the test and that redefinition included another call to loadFixtures, but for a different data class and without the exclusion :
<?php
namespace App\Tests\Controller;
use App\DataFixtures\DiscountFixtures;
class DiscountControllerWebTest extends AbstractPantherTest
{
function setUp():void
{
parent::setUp();
$this->loadFixtures([
DiscountFixtures::class,
]);
}

(Symfony 4) How to implement a constants class

I'm trying to have constants everywhere in my code so I don't have to just stick numbers, I know that's bad practice.
So in my root folder I put a class constants, like this:
namespace App;
class Constants{
public const FREE_TIER = 0;
}
So I include the "use App\Constants;" in my repository class.
Here is the function I try to access my constants class in:
use App\Constants; /* earlier on */
/**
* #param User $user
* #return array
*/
public function countFreeTiers() : array
{
$qb = $this->createQueryBuilder('t');
$qb->select('COUNT(t.tierNumber)')
->where('t.tierNumber = :freeTier')
->groupBy('t.tierNumber')
->orderBy('t.tierNumber', 'ASC')
->setParameter('freeTier', Constants::FREE_TIER /* error here */)
->setParameter('true', true);
$query = $qb->getQuery();
return $query->getResult();
}
This is the error I get:
Attempted to load class "Constants" from namespace "App".
Did you forget a "use" statement for another namespace?
Am I not allowed to just use the "App" namespace?
This is cerad's solution, not mine.
My problem was that my Constants.php was in the root folder of the project.
I had to move the Constants.php file to inside the src folder, so putting it at the root of src (as opposed to the root of the project) fixed it.
You can try to put the class file into 'src/Utilities' and symfony will auto load it.

Bundle to add attribute to another entity

Hi,
I have an entity A :
id
att1
att2
Now, I'd like to add a new Bundle (which will add new functionality) and here especially I'd like to add an attribute to A. A must be like :
id
att1
att2
newAtt3
newAtt4
In order to do that, I was thinking to create a new entity which will extend A and add the new attribute.
But then, what I don't know is how can I prepare the first bundle to use the 2nd entity (and controller/view) if the 2nd bundle is installed?
I guess I need to add configuration in the first bundle, but I have no idea what to add...
Thanks !
Please read Best Practices for Reusable Bundles
and Doctrine Inheritance Mapping
You can also think about Traits but often the best way is to use Interfaces. With the help of interfaces you can make your bundle highly configurable on a clean way like this:
make a configuration variabele that tells the bundle what class should be used. This can be the default class A from the Bundle but may also be class A from your AppBundle.
$rootNode
->children()
->scalarNode('a_entity')
->defaultValue('AppBundle\\Entity\\A')
->end()
->end()
;
Then make a interface for class A with all the functions that are mandatory:
interface AInterface
{
public function setVariable($name, $var);
public function getHtml($template);
}
and implement the interface in the class:
class A implements AInterface
{
// ...
}
Every time if you pass the class as a paramter use AInterface instead of A:
class B
{
private $a;
public function __construct(AInterface $a)
{
$this->a = $a;
}
}
Right now you can change the configuration variabele a_entity to another class. This other class still needs to implement the interface AInterface.

using google analytics in laravel project

hey guys i'm trying to use google analytics in my project but i always get an error : Argument 1 passed to Spatie\LaravelAnalytics\LaravelAnalytics::__construct() must be an instance of Spatie\LaravelAnalytics\GoogleApiHelper, none given
actually i don't know how to deal with that error as it's my first time to use it .
that's simply the code i've written :
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Carbon\Carbon;
use Illuminate\Http\Request;
use App\Product;
use App\ProductTrans;
use App\Service;
use Spatie\LaravelAnalytics\LaravelAnalytics;
class HomeController extends Controller {
//
public function getIndex() {
$services = Service::get();
$products = Product::get();
$analyticsData =new LaravelAnalytics();
$analyticsData->getVisitorsAndPageViews();
dd($analyticsData);
return view('admin.pages.home',compact('services','products'));
}
so can anyone help me ?

Where to check if a class is loaded or not?

In HasRoleRepository.php :
use \XXX\MyBundle\Model\Role_RT;
use \XXX\MyBundle\Model\Role;
...
public static function toModelClass($hasRoleArray, $RefGroupeRtArray) {
$roles = array();
foreach($hasRoleArray as $hasRole) {
$role = $hasRole->getIdRole()->getId() === 1 ? new Role_RT() : new Role();
....
}
I have a fatal error : Error: Class 'XXX\MyBundle\Model\Role_RT' not found in \src\XXX\MyBundle\Repository\HasRoleRepository.php line 37
No problem with the Role class, it is just with the Role_RT class.
Same namespace in Role and Role_RT :
namespace XXX\MyBundle\Model;
I do not understand. this one is not loaded. why ? how ?
Thank you
It's considered a bad practice to use _ in Class Names meaning Symfony doesn't detected it (because it's build to prevent bad practices). Change your Model name to RoleRT and try again.
I agree with Splendonia. If you want to use Symfony (and most generally Composer) you will have to do with the PSR-0 naming conventions.
Please have a look to :
http://symfony.com/doc/current/contributing/code/standards.html#naming-conventions
http://www.php-fig.org/psr/psr-0/

Resources